diff --git a/README.md b/README.md index 406447b..5925ae8 100644 --- a/README.md +++ b/README.md @@ -11,12 +11,41 @@ It's # Differences from Flute -- Added: - - React-like fragment `(<> ...)`. It lets you group elements without a wrapper element. +- New features: + - Fragment `(<> ...)`. It allows you to group elements without a wrapper element. - Boolean attributes support (e.g. `checked`, `disabled`). If the value is - `nil`: Nothing is rendered. - `t`: Only the key is rendered. - non-boolean: The key/value pair is rendered. + - `...props` alist. It allows you to pass props more flexibly. + +```lisp +(<> + (div) + (div)) + +;
+: + +(define-element view-more () + (a ...props + "View More")) + +(view-more :href "/detail" :class "m-1") + +; View More + +(define-element custom-button (variant) + (button `((:class . ,variant) + ,@...props) + children)) + +(custom-button :type "submit" :variant "big" :onclick "doSomething()" + "Submit") + +; +``` + - Improved: - Element functions are wrapped in macros for natural indentation. - Bugfix. https://github.com/ailisp/flute/issues/5, https://github.com/ailisp/flute/issues/7 diff --git a/src/elements.lisp b/src/elements.lisp index e909426..69adf90 100644 --- a/src/elements.lisp +++ b/src/elements.lisp @@ -9,6 +9,7 @@ #:tag #:children #:attrs + #:...props #:attrs-alist #:make-attrs #:copy-attrs @@ -192,7 +193,7 @@ style sub summary sup svg table tbody td template textarea tfoot th thead |time| title tr track u ul var video wbr) -(defmacro define-element (name (&rest args) &body body) +(defmacro define-element (name (&rest props) &body body) (let ((%name (alx:symbolicate '% name)) (attrs (gensym "attrs")) (children (gensym "children")) @@ -209,10 +210,17 @@ (declare (ignorable tag attrs)) (let ((children (and ,raw-children (apply #'%<> ,raw-children)))) (declare (ignorable children)) - (let ,(mapcar (lambda (arg) - (list arg `(attr attrs (alx:make-keyword ',arg)))) - args) - (progn ,@body))))))) + (let ,(mapcar (lambda (prop) + (list prop `(attr attrs (alx:make-keyword ',prop)))) + props) + (let ((...props + (loop :for (key . value) in (attrs-alist attrs) + :unless (member key + ',(mapcar #'alx:make-keyword + props)) + :collect (cons key value)))) + (declare (ignorable ...props)) + (progn ,@body)))))))) (defmacro ,name (&body attrs-and-children) `(,',%name ,@attrs-and-children)))))