@@ -6,7 +6,7 @@ use quote::{quote, quote_spanned, ToTokens};
66use syn:: parse:: { Parse , ParseBuffer , ParseStream } ;
77use syn:: spanned:: Spanned ;
88use syn:: token:: Brace ;
9- use syn:: { braced, Block , Expr , ExprBlock , ExprMacro , ExprPath , ExprRange , Stmt , Token } ;
9+ use syn:: { braced, Block , Expr , ExprBlock , ExprMacro , ExprPath , ExprRange , Stmt , Token , LitStr , parse_quote } ;
1010
1111use crate :: html_tree:: HtmlDashedName ;
1212use crate :: stringify:: Stringify ;
@@ -27,6 +27,12 @@ impl From<HtmlDashedName> for PropLabel {
2727 }
2828}
2929
30+ impl From < LitStr > for PropLabel {
31+ fn from ( value : LitStr ) -> Self {
32+ Self :: Dynamic ( parse_quote ! { #value } )
33+ }
34+ }
35+
3036impl TryFrom < PropLabel > for HtmlDashedName {
3137 type Error = ( ) ;
3238
@@ -100,7 +106,9 @@ impl Parse for Prop {
100106 . map ( PropDirective :: ApplyAsProperty )
101107 . ok ( ) ;
102108 if input. peek ( Brace ) {
103- Self :: parse_shorthand_or_dynamic_prop_assignment ( input, directive)
109+ Self :: parse_shorthand_or_expr_dynamic_prop_assignment ( input, directive)
110+ } else if input. peek ( LitStr ) {
111+ Self :: parse_literal_dynamic_prop_assignment ( input, directive)
104112 } else {
105113 Self :: parse_prop_assignment ( input, directive)
106114 }
@@ -114,7 +122,7 @@ impl Prop {
114122 ///
115123 /// Shorthand syntax only allows for labels with no hyphens,
116124 /// as it would otherwise create an ambiguity in the syntax.
117- fn parse_shorthand_or_dynamic_prop_assignment (
125+ fn parse_shorthand_or_expr_dynamic_prop_assignment (
118126 input : ParseStream ,
119127 directive : Option < PropDirective > ,
120128 ) -> syn:: Result < Self > {
@@ -163,6 +171,37 @@ impl Prop {
163171 } )
164172 }
165173
174+ /// Parse a prop of the form `"label"={value}`
175+ fn parse_literal_dynamic_prop_assignment (
176+ input : ParseStream ,
177+ directive : Option < PropDirective > ,
178+ ) -> syn:: Result < Self > {
179+ let label = input. parse :: < LitStr > ( ) ?;
180+ let equals = input. parse :: < Token ! [ =] > ( ) . map_err ( |_| {
181+ let display = label. stringify ( ) ;
182+ syn:: Error :: new_spanned (
183+ & label,
184+ format ! (
185+ "`{display}` doesn't have a value. (hint: set the value to `true` or `false` \
186+ for boolean attributes)"
187+ ) ,
188+ )
189+ } ) ?;
190+ if input. is_empty ( ) {
191+ return Err ( syn:: Error :: new_spanned (
192+ equals,
193+ "expected an expression following this equals sign" ,
194+ ) ) ;
195+ }
196+
197+ let value = parse_prop_value ( input) ?;
198+ Ok ( Self {
199+ label : label. into ( ) ,
200+ value,
201+ directive,
202+ } )
203+ }
204+
166205 /// Parse a prop of the form `label={value}`
167206 fn parse_prop_assignment (
168207 input : ParseStream ,
0 commit comments