; Self-closing JSX with props: <Input type="email" placeholder="..." />
(jsx_self_closing_element
  name: (identifier) @el.tag
  (jsx_attribute
    (property_identifier) @el.prop.name
    [(string (string_fragment) @el.prop.value.str)
     (jsx_expression (_) @el.prop.value.expr)])) @el.self

; Opening JSX with props: <Button variant="destructive">
(jsx_opening_element
  name: (identifier) @el.tag
  (jsx_attribute
    (property_identifier) @el.prop.name
    [(string (string_fragment) @el.prop.value.str)
     (jsx_expression (_) @el.prop.value.expr)])) @el.open

; Self-closing JSX without props: <Shell />, <DuetLogo />
; Captures the element so composition wrappers / providers / shells appear
; in deep elements. The consumer keys by position, so this match coexists
; with the prop-bearing pattern above when both apply.
(jsx_self_closing_element
  name: (identifier) @el.tag) @el.self

; Opening JSX without props: <Shell>children</Shell>
(jsx_opening_element
  name: (identifier) @el.tag) @el.open

; JSX text content (direct text inside elements)
(jsx_element
  (jsx_opening_element
    name: (identifier) @el.text.tag)
  (jsx_text) @el.text.content)
