stimeo-ui 0.15.0 → 0.16.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (267) hide show
  1. package/CHANGELOG.md +178 -0
  2. package/README.md +120 -0
  3. package/dist/cable/index.js +63 -15
  4. package/dist/cable/index.js.map +1 -1
  5. package/dist/controllers/accordion_controller.d.ts +30 -3
  6. package/dist/controllers/accordion_controller.js +98 -9
  7. package/dist/controllers/accordion_controller.js.map +1 -1
  8. package/dist/controllers/alert_dialog_controller.d.ts +8 -7
  9. package/dist/controllers/alert_dialog_controller.js.map +1 -1
  10. package/dist/controllers/announcer_controller.d.ts +3 -2
  11. package/dist/controllers/announcer_controller.js +8 -1
  12. package/dist/controllers/announcer_controller.js.map +1 -1
  13. package/dist/controllers/auto_submit_controller.js +43 -2
  14. package/dist/controllers/auto_submit_controller.js.map +1 -1
  15. package/dist/controllers/avatar_controller.js +1 -1
  16. package/dist/controllers/avatar_controller.js.map +1 -1
  17. package/dist/controllers/breadcrumb_controller.d.ts +10 -7
  18. package/dist/controllers/breadcrumb_controller.js +9 -8
  19. package/dist/controllers/breadcrumb_controller.js.map +1 -1
  20. package/dist/controllers/bulk_select_controller.d.ts +4 -4
  21. package/dist/controllers/bulk_select_controller.js +7 -6
  22. package/dist/controllers/bulk_select_controller.js.map +1 -1
  23. package/dist/controllers/calendar_controller.d.ts +85 -23
  24. package/dist/controllers/calendar_controller.js +323 -123
  25. package/dist/controllers/calendar_controller.js.map +1 -1
  26. package/dist/controllers/carousel_controller.d.ts +67 -22
  27. package/dist/controllers/carousel_controller.js +263 -38
  28. package/dist/controllers/carousel_controller.js.map +1 -1
  29. package/dist/controllers/character_counter_controller.d.ts +1 -1
  30. package/dist/controllers/character_counter_controller.js +40 -2
  31. package/dist/controllers/character_counter_controller.js.map +1 -1
  32. package/dist/controllers/checkbox_controller.js +54 -10
  33. package/dist/controllers/checkbox_controller.js.map +1 -1
  34. package/dist/controllers/clipboard_controller.d.ts +28 -2
  35. package/dist/controllers/clipboard_controller.js +63 -5
  36. package/dist/controllers/clipboard_controller.js.map +1 -1
  37. package/dist/controllers/collapsible_controller.d.ts +25 -1
  38. package/dist/controllers/collapsible_controller.js +99 -14
  39. package/dist/controllers/collapsible_controller.js.map +1 -1
  40. package/dist/controllers/color_picker_controller.d.ts +29 -8
  41. package/dist/controllers/color_picker_controller.js +80 -34
  42. package/dist/controllers/color_picker_controller.js.map +1 -1
  43. package/dist/controllers/combobox_controller.d.ts +10 -1
  44. package/dist/controllers/combobox_controller.js +106 -16
  45. package/dist/controllers/combobox_controller.js.map +1 -1
  46. package/dist/controllers/command_palette_controller.d.ts +3 -3
  47. package/dist/controllers/command_palette_controller.js +35 -3
  48. package/dist/controllers/command_palette_controller.js.map +1 -1
  49. package/dist/controllers/conditional_fields_controller.js +56 -11
  50. package/dist/controllers/conditional_fields_controller.js.map +1 -1
  51. package/dist/controllers/confirm_controller.js +3 -0
  52. package/dist/controllers/confirm_controller.js.map +1 -1
  53. package/dist/controllers/context_menu_controller.d.ts +6 -0
  54. package/dist/controllers/context_menu_controller.js +32 -12
  55. package/dist/controllers/context_menu_controller.js.map +1 -1
  56. package/dist/controllers/countdown_controller.d.ts +30 -1
  57. package/dist/controllers/countdown_controller.js +129 -26
  58. package/dist/controllers/countdown_controller.js.map +1 -1
  59. package/dist/controllers/currency_input_controller.d.ts +74 -15
  60. package/dist/controllers/currency_input_controller.js +205 -58
  61. package/dist/controllers/currency_input_controller.js.map +1 -1
  62. package/dist/controllers/data_grid_controller.d.ts +63 -18
  63. package/dist/controllers/data_grid_controller.js +195 -29
  64. package/dist/controllers/data_grid_controller.js.map +1 -1
  65. package/dist/controllers/date_range_picker_controller.d.ts +34 -6
  66. package/dist/controllers/date_range_picker_controller.js +139 -27
  67. package/dist/controllers/date_range_picker_controller.js.map +1 -1
  68. package/dist/controllers/dialog_controller.d.ts +10 -3
  69. package/dist/controllers/dialog_controller.js +35 -8
  70. package/dist/controllers/dialog_controller.js.map +1 -1
  71. package/dist/controllers/direct_upload_controller.js +22 -4
  72. package/dist/controllers/direct_upload_controller.js.map +1 -1
  73. package/dist/controllers/dirty_form_controller.d.ts +2 -2
  74. package/dist/controllers/dirty_form_controller.js +14 -1
  75. package/dist/controllers/dirty_form_controller.js.map +1 -1
  76. package/dist/controllers/dismissible_controller.js +1 -0
  77. package/dist/controllers/dismissible_controller.js.map +1 -1
  78. package/dist/controllers/drawer_controller.d.ts +18 -10
  79. package/dist/controllers/drawer_controller.js +54 -19
  80. package/dist/controllers/drawer_controller.js.map +1 -1
  81. package/dist/controllers/dropdown_controller.d.ts +9 -3
  82. package/dist/controllers/dropdown_controller.js +36 -9
  83. package/dist/controllers/dropdown_controller.js.map +1 -1
  84. package/dist/controllers/editable_controller.js +34 -0
  85. package/dist/controllers/editable_controller.js.map +1 -1
  86. package/dist/controllers/file_dropzone_controller.js +144 -51
  87. package/dist/controllers/file_dropzone_controller.js.map +1 -1
  88. package/dist/controllers/filter_controller.d.ts +10 -4
  89. package/dist/controllers/filter_controller.js +20 -6
  90. package/dist/controllers/filter_controller.js.map +1 -1
  91. package/dist/controllers/flash_controller.d.ts +26 -6
  92. package/dist/controllers/flash_controller.js +305 -46
  93. package/dist/controllers/flash_controller.js.map +1 -1
  94. package/dist/controllers/focus_controller.js +1 -0
  95. package/dist/controllers/focus_controller.js.map +1 -1
  96. package/dist/controllers/form_field_controller.js +7 -5
  97. package/dist/controllers/form_field_controller.js.map +1 -1
  98. package/dist/controllers/form_validation_controller.js +19 -13
  99. package/dist/controllers/form_validation_controller.js.map +1 -1
  100. package/dist/controllers/frame_loading_controller.js +16 -2
  101. package/dist/controllers/frame_loading_controller.js.map +1 -1
  102. package/dist/controllers/highlight_controller.js +19 -2
  103. package/dist/controllers/highlight_controller.js.map +1 -1
  104. package/dist/controllers/hover_card_controller.d.ts +10 -2
  105. package/dist/controllers/hover_card_controller.js +40 -14
  106. package/dist/controllers/hover_card_controller.js.map +1 -1
  107. package/dist/controllers/idle_controller.d.ts +16 -3
  108. package/dist/controllers/idle_controller.js +90 -5
  109. package/dist/controllers/idle_controller.js.map +1 -1
  110. package/dist/controllers/input_mask_controller.d.ts +5 -2
  111. package/dist/controllers/input_mask_controller.js +65 -9
  112. package/dist/controllers/input_mask_controller.js.map +1 -1
  113. package/dist/controllers/intersection_controller.js +3 -0
  114. package/dist/controllers/intersection_controller.js.map +1 -1
  115. package/dist/controllers/lazy_frame_controller.js +11 -2
  116. package/dist/controllers/lazy_frame_controller.js.map +1 -1
  117. package/dist/controllers/listbox_controller.d.ts +50 -8
  118. package/dist/controllers/listbox_controller.js +203 -45
  119. package/dist/controllers/listbox_controller.js.map +1 -1
  120. package/dist/controllers/masonry_controller.js +0 -2
  121. package/dist/controllers/masonry_controller.js.map +1 -1
  122. package/dist/controllers/menu_controller.d.ts +9 -3
  123. package/dist/controllers/menu_controller.js +45 -16
  124. package/dist/controllers/menu_controller.js.map +1 -1
  125. package/dist/controllers/menubar_controller.d.ts +11 -0
  126. package/dist/controllers/menubar_controller.js +58 -24
  127. package/dist/controllers/menubar_controller.js.map +1 -1
  128. package/dist/controllers/meter_controller.js +9 -5
  129. package/dist/controllers/meter_controller.js.map +1 -1
  130. package/dist/controllers/multi_select_controller.d.ts +18 -3
  131. package/dist/controllers/multi_select_controller.js +278 -104
  132. package/dist/controllers/multi_select_controller.js.map +1 -1
  133. package/dist/controllers/navigation_menu_controller.d.ts +11 -0
  134. package/dist/controllers/navigation_menu_controller.js +48 -15
  135. package/dist/controllers/navigation_menu_controller.js.map +1 -1
  136. package/dist/controllers/nested_form_controller.js +37 -8
  137. package/dist/controllers/nested_form_controller.js.map +1 -1
  138. package/dist/controllers/network_status_controller.js +9 -1
  139. package/dist/controllers/network_status_controller.js.map +1 -1
  140. package/dist/controllers/number_input_controller.d.ts +36 -8
  141. package/dist/controllers/number_input_controller.js +124 -21
  142. package/dist/controllers/number_input_controller.js.map +1 -1
  143. package/dist/controllers/optimistic_controller.js +14 -1
  144. package/dist/controllers/optimistic_controller.js.map +1 -1
  145. package/dist/controllers/otp_controller.d.ts +22 -7
  146. package/dist/controllers/otp_controller.js +198 -55
  147. package/dist/controllers/otp_controller.js.map +1 -1
  148. package/dist/controllers/overflow_indicator_controller.d.ts +8 -12
  149. package/dist/controllers/overflow_indicator_controller.js +84 -13
  150. package/dist/controllers/overflow_indicator_controller.js.map +1 -1
  151. package/dist/controllers/overflow_menu_controller.d.ts +26 -6
  152. package/dist/controllers/overflow_menu_controller.js +112 -41
  153. package/dist/controllers/overflow_menu_controller.js.map +1 -1
  154. package/dist/controllers/pagination_controller.d.ts +19 -11
  155. package/dist/controllers/pagination_controller.js +74 -28
  156. package/dist/controllers/pagination_controller.js.map +1 -1
  157. package/dist/controllers/password_reveal_controller.d.ts +15 -1
  158. package/dist/controllers/password_reveal_controller.js +59 -2
  159. package/dist/controllers/password_reveal_controller.js.map +1 -1
  160. package/dist/controllers/persist_controller.js +30 -8
  161. package/dist/controllers/persist_controller.js.map +1 -1
  162. package/dist/controllers/pointer_drag_controller.js +131 -52
  163. package/dist/controllers/pointer_drag_controller.js.map +1 -1
  164. package/dist/controllers/popover_controller.d.ts +9 -3
  165. package/dist/controllers/popover_controller.js +45 -11
  166. package/dist/controllers/popover_controller.js.map +1 -1
  167. package/dist/controllers/portal_controller.d.ts +1 -1
  168. package/dist/controllers/portal_controller.js +6 -2
  169. package/dist/controllers/portal_controller.js.map +1 -1
  170. package/dist/controllers/preview_guard_controller.js +16 -1
  171. package/dist/controllers/preview_guard_controller.js.map +1 -1
  172. package/dist/controllers/progress_controller.js +8 -4
  173. package/dist/controllers/progress_controller.js.map +1 -1
  174. package/dist/controllers/radio_group_controller.d.ts +6 -4
  175. package/dist/controllers/radio_group_controller.js +42 -17
  176. package/dist/controllers/radio_group_controller.js.map +1 -1
  177. package/dist/controllers/range_slider_controller.d.ts +49 -1
  178. package/dist/controllers/range_slider_controller.js +88 -42
  179. package/dist/controllers/range_slider_controller.js.map +1 -1
  180. package/dist/controllers/rating_controller.d.ts +14 -3
  181. package/dist/controllers/rating_controller.js +39 -15
  182. package/dist/controllers/rating_controller.js.map +1 -1
  183. package/dist/controllers/read_more_controller.d.ts +24 -2
  184. package/dist/controllers/read_more_controller.js +69 -2
  185. package/dist/controllers/read_more_controller.js.map +1 -1
  186. package/dist/controllers/resizable_controller.d.ts +16 -2
  187. package/dist/controllers/resizable_controller.js +82 -22
  188. package/dist/controllers/resizable_controller.js.map +1 -1
  189. package/dist/controllers/scroll_area_controller.js +5 -1
  190. package/dist/controllers/scroll_area_controller.js.map +1 -1
  191. package/dist/controllers/scroll_visibility_controller.js +0 -1
  192. package/dist/controllers/scroll_visibility_controller.js.map +1 -1
  193. package/dist/controllers/scrollspy_controller.d.ts +3 -2
  194. package/dist/controllers/scrollspy_controller.js +6 -0
  195. package/dist/controllers/scrollspy_controller.js.map +1 -1
  196. package/dist/controllers/separator_controller.d.ts +41 -14
  197. package/dist/controllers/separator_controller.js +66 -37
  198. package/dist/controllers/separator_controller.js.map +1 -1
  199. package/dist/controllers/sidebar_controller.d.ts +20 -3
  200. package/dist/controllers/sidebar_controller.js +77 -18
  201. package/dist/controllers/sidebar_controller.js.map +1 -1
  202. package/dist/controllers/skeleton_controller.js +6 -1
  203. package/dist/controllers/skeleton_controller.js.map +1 -1
  204. package/dist/controllers/slider_controller.d.ts +45 -7
  205. package/dist/controllers/slider_controller.js +82 -47
  206. package/dist/controllers/slider_controller.js.map +1 -1
  207. package/dist/controllers/smart_sticky_header_controller.js +11 -1
  208. package/dist/controllers/smart_sticky_header_controller.js.map +1 -1
  209. package/dist/controllers/sortable_controller.js +17 -2
  210. package/dist/controllers/sortable_controller.js.map +1 -1
  211. package/dist/controllers/spinner_controller.js +10 -2
  212. package/dist/controllers/spinner_controller.js.map +1 -1
  213. package/dist/controllers/step_indicator_controller.d.ts +19 -17
  214. package/dist/controllers/step_indicator_controller.js +18 -17
  215. package/dist/controllers/step_indicator_controller.js.map +1 -1
  216. package/dist/controllers/stepper_controller.d.ts +34 -9
  217. package/dist/controllers/stepper_controller.js +101 -19
  218. package/dist/controllers/stepper_controller.js.map +1 -1
  219. package/dist/controllers/stick_to_bottom_controller.d.ts +19 -0
  220. package/dist/controllers/stick_to_bottom_controller.js +75 -5
  221. package/dist/controllers/stick_to_bottom_controller.js.map +1 -1
  222. package/dist/controllers/submit_once_controller.d.ts +3 -2
  223. package/dist/controllers/submit_once_controller.js +16 -3
  224. package/dist/controllers/submit_once_controller.js.map +1 -1
  225. package/dist/controllers/switch_controller.d.ts +29 -7
  226. package/dist/controllers/switch_controller.js +101 -10
  227. package/dist/controllers/switch_controller.js.map +1 -1
  228. package/dist/controllers/tabs_controller.d.ts +12 -0
  229. package/dist/controllers/tabs_controller.js +21 -2
  230. package/dist/controllers/tabs_controller.js.map +1 -1
  231. package/dist/controllers/tags_input_controller.d.ts +15 -3
  232. package/dist/controllers/tags_input_controller.js +209 -59
  233. package/dist/controllers/tags_input_controller.js.map +1 -1
  234. package/dist/controllers/theme_controller.d.ts +20 -3
  235. package/dist/controllers/theme_controller.js +64 -14
  236. package/dist/controllers/theme_controller.js.map +1 -1
  237. package/dist/controllers/time_picker_controller.js +23 -8
  238. package/dist/controllers/time_picker_controller.js.map +1 -1
  239. package/dist/controllers/toast_controller.d.ts +52 -15
  240. package/dist/controllers/toast_controller.js +337 -54
  241. package/dist/controllers/toast_controller.js.map +1 -1
  242. package/dist/controllers/toggle_group_controller.d.ts +49 -7
  243. package/dist/controllers/toggle_group_controller.js +159 -23
  244. package/dist/controllers/toggle_group_controller.js.map +1 -1
  245. package/dist/controllers/toolbar_controller.js +32 -0
  246. package/dist/controllers/toolbar_controller.js.map +1 -1
  247. package/dist/controllers/tooltip_controller.d.ts +8 -0
  248. package/dist/controllers/tooltip_controller.js +39 -13
  249. package/dist/controllers/tooltip_controller.js.map +1 -1
  250. package/dist/controllers/transition_controller.js +4 -0
  251. package/dist/controllers/transition_controller.js.map +1 -1
  252. package/dist/controllers/tree_view_controller.d.ts +39 -8
  253. package/dist/controllers/tree_view_controller.js +169 -16
  254. package/dist/controllers/tree_view_controller.js.map +1 -1
  255. package/dist/index.d.ts +28 -1
  256. package/dist/index.js +4588 -1535
  257. package/dist/index.js.map +1 -1
  258. package/dist/inspector/cli.d.ts +72 -6
  259. package/dist/inspector/cli.js +262 -51
  260. package/dist/inspector/cli.js.map +1 -1
  261. package/dist/inspector/cli_bin.js +309 -51
  262. package/dist/inspector/cli_bin.js.map +1 -1
  263. package/dist/inspector/examples.json +40 -40
  264. package/dist/inspector/manifest.json +525 -59
  265. package/dist/positioning/index.js +2 -0
  266. package/dist/positioning/index.js.map +1 -1
  267. package/package.json +2 -2
@@ -38,6 +38,8 @@ interface ControllerManifest {
38
38
  readonly valueSyntaxConstraints?: readonly StringSyntaxConstraint[];
39
39
  /** Statically decidable relationships between literal Stimulus Values. */
40
40
  readonly valueRelations: readonly ValueRelation[];
41
+ /** What each action reads out of `event.params`. */
42
+ readonly actionParams: readonly ActionParamRule[];
41
43
  /**
42
44
  * Public action method names declared via `static actions`, wired by
43
45
  * consumers as `data-action="…-><identifier>#<action>"`.
@@ -55,6 +57,11 @@ interface ControllerManifest {
55
57
  * {@link ConditionalTargetRule}.
56
58
  */
57
59
  readonly conditionalTargets: readonly ConditionalTargetRule[];
60
+ /**
61
+ * `<template>` targets whose content must be exactly one row. See
62
+ * {@link TemplateRootRule}.
63
+ */
64
+ readonly templateRoots: readonly TemplateRootRule[];
58
65
  /**
59
66
  * Actions required on a particular element in one Value configuration. See
60
67
  * {@link RequiredActionRule}.
@@ -592,6 +599,33 @@ interface ForbiddenAriaRule {
592
599
  /** Human-readable fix suggestion shown by the CLI (stage 4). */
593
600
  readonly suggestion: string;
594
601
  }
602
+ /**
603
+ * One `event.params` entry an action reads, written as the author writes it.
604
+ *
605
+ * Stimulus builds `event.params` from `data-<identifier>-<param>-param` attributes
606
+ * on the element carrying the `data-action`. Nothing about that spelling is
607
+ * reflected, so a name that never arrives is indistinguishable at runtime from one
608
+ * the author never meant to pass: the action runs and returns, and the control is
609
+ * dead with no diagnostic anywhere.
610
+ *
611
+ * `required` is reserved for an action that has **no other way** to reach the value.
612
+ * Where the reader falls back to `event.detail` or to an attribute, the param is
613
+ * genuinely optional and a page driving the action that way is correct.
614
+ */
615
+ interface ActionParamRule {
616
+ /** The action method the param belongs to; must appear in `actions`. */
617
+ readonly action: string;
618
+ /** The param name, camelCase, as `event.params` reads it. */
619
+ readonly param: string;
620
+ /** Whether the action can reach the value no other way. */
621
+ readonly required?: boolean;
622
+ /** The literal values the reader accepts, when it accepts a fixed set. */
623
+ readonly allowedValues?: readonly string[];
624
+ /** Whether the reader takes a whole number and returns on anything else. */
625
+ readonly integer?: boolean;
626
+ /** Human-readable fix suggestion shown by the CLI. */
627
+ readonly suggestion: string;
628
+ }
595
629
  /**
596
630
  * The bundled manifest. `schemaVersion` tracks the manifest *format*;
597
631
  * `packageVersion` tracks the `stimeo-ui` release it was generated from so a
@@ -603,6 +637,24 @@ interface Manifest {
603
637
  /** Keyed by controller identifier, e.g. `stimeo--menu`. */
604
638
  readonly controllers: Readonly<Record<string, ControllerManifest>>;
605
639
  }
640
+ /**
641
+ * The shape a `<template>` target's content has to have: **exactly one element**,
642
+ * which is the row the controller clones.
643
+ *
644
+ * A row is cloned on its own so that the node appended is the node a later
645
+ * removal takes back. Content the row does not cover — a second element, a
646
+ * wrapper around it — is therefore never rendered, and the widget silently adds
647
+ * nothing. A controller that reports it names it on the console once per
648
+ * connection; this rule says so before the page is served.
649
+ */
650
+ interface TemplateRootRule {
651
+ /** Target name of the `<template>`. */
652
+ readonly template: string;
653
+ /** Target name its one element must carry, when the row is a declared part. */
654
+ readonly rootTarget?: string;
655
+ /** What to write instead. */
656
+ readonly suggestion: string;
657
+ }
606
658
  /**
607
659
  * A target requirement that only exists once another *optional* target is
608
660
  * present.
@@ -625,8 +677,8 @@ interface ConditionalTargetRule {
625
677
  /** Targets that become required once {@link whenPresent} appears. */
626
678
  readonly require: readonly string[];
627
679
  /**
628
- * Require each {@link require} entry to sit **inside** the `whenPresent`
629
- * element rather than anywhere in the scope.
680
+ * Require each {@link ConditionalTargetRule.require | require} entry to sit
681
+ * **inside** the `whenPresent` element rather than anywhere in the scope.
630
682
  *
631
683
  * A `<template>` is cloned at runtime, so a part declared outside it never
632
684
  * reaches the clone. Without this the presence check passes on markup the
@@ -634,9 +686,9 @@ interface ConditionalTargetRule {
634
686
  */
635
687
  readonly requireInside?: boolean;
636
688
  /**
637
- * Require each {@link require} entry to share its nearest enclosing host —
638
- * the closest ancestor matching one of these selectors — with the
639
- * `whenPresent` element.
689
+ * Require each {@link ConditionalTargetRule.require | require} entry to share its
690
+ * nearest enclosing host — the closest ancestor matching one of these selectors —
691
+ * with the `whenPresent` element.
640
692
  *
641
693
  * Neither presence nor {@link requireInside} can express a pair that must sit
642
694
  * in the *same* container without being nested in one another. A controller
@@ -650,6 +702,20 @@ interface ConditionalTargetRule {
650
702
  * generated — reporting either would be a guess, and the check stays quiet.
651
703
  */
652
704
  readonly requireSameHost?: readonly HostSelector[];
705
+ /**
706
+ * Require each {@link ConditionalTargetRule.require | require} entry to sit
707
+ * inside the same element carrying this controller's target of this name as the
708
+ * {@link whenPresent} entry does.
709
+ *
710
+ * Where {@link requireSameHost} describes the host by tag, this names it: the host
711
+ * is a declared target of the same controller, so a pair resolved per trigger can
712
+ * say so directly. Halves split across two of those hosts leave both incomplete,
713
+ * and neither swaps.
714
+ *
715
+ * A scope whose hosts are all generated leaves the question undecidable, so nothing
716
+ * is reported there.
717
+ */
718
+ readonly requireSameTargetHost?: string;
653
719
  /**
654
720
  * What to call the shared host in the diagnostic (e.g. `submit control`).
655
721
  * The selectors' tag names read as a disjunction of element names, which
@@ -806,7 +872,7 @@ type DiagnosticSeverity = "error" | "warning";
806
872
  * for testing, machine-readable output, and `data-stimeo-ignore` suppression
807
873
  * lists (which is why the set also exists as a runtime array).
808
874
  */
809
- declare const DIAGNOSTIC_CODES: readonly ["unknown-controller", "unknown-target", "unknown-value", "invalid-value", "unknown-action-controller", "unknown-action-method", "orphan-target", "missing-required-target", "missing-conditional-target", "missing-required-action", "missing-action-completion", "missing-action-event", "missing-aria", "invalid-aria-value", "keyboard-inaccessible", "invalid-host", "unresolved-idref", "managed-aria", "composition-mismatch", "missing-companion", "undeclared-target", "cardinality-violation", "forbidden-aria", "missing-announcer", "unknown-ignore-code"];
875
+ declare const DIAGNOSTIC_CODES: readonly ["unknown-controller", "unknown-target", "unknown-value", "invalid-value", "unknown-action-controller", "unknown-action-method", "unknown-action-event", "orphan-target", "missing-required-target", "missing-conditional-target", "invalid-template-root", "missing-required-action", "missing-action-completion", "missing-action-event", "missing-aria", "invalid-aria-value", "keyboard-inaccessible", "invalid-host", "unresolved-idref", "managed-aria", "composition-mismatch", "missing-companion", "undeclared-target", "cardinality-violation", "forbidden-aria", "missing-announcer", "missing-action-param", "invalid-action-param", "confusable-action-param", "unknown-ignore-code"];
810
876
  /** See {@link DIAGNOSTIC_CODES}. */
811
877
  type DiagnosticCode = (typeof DIAGNOSTIC_CODES)[number];
812
878
  /**
@@ -980,12 +980,24 @@ var NAMESPACE_PREFIX = "stimeo--";
980
980
  function dasherize(value) {
981
981
  return value.replace(/([A-Z])/g, (_match, char) => `-${char.toLowerCase()}`);
982
982
  }
983
- function controllerIdentifiers(dataControllerValue) {
983
+ function attributeTokens(value) {
984
+ const tokens = [];
984
985
  const seen = /* @__PURE__ */ new Set();
985
- for (const token of dataControllerValue.split(/\s+/)) {
986
- if (token.startsWith(NAMESPACE_PREFIX)) seen.add(token);
986
+ const pattern = /\S+/g;
987
+ for (let match = pattern.exec(value); match; match = pattern.exec(value)) {
988
+ if (seen.has(match[0])) continue;
989
+ seen.add(match[0]);
990
+ tokens.push({ name: match[0], start: match.index });
987
991
  }
988
- return [...seen];
992
+ return tokens;
993
+ }
994
+ function controllerIdentifiers(dataControllerValue) {
995
+ return controllerIdentifierTokens(dataControllerValue).map((token) => token.name);
996
+ }
997
+ function controllerIdentifierTokens(dataControllerValue) {
998
+ return attributeTokens(dataControllerValue).filter(
999
+ (token) => token.name.startsWith(NAMESPACE_PREFIX)
1000
+ );
989
1001
  }
990
1002
  function parseTargetAttr(attrName) {
991
1003
  const match = /^data-(stimeo--[a-z0-9][a-z0-9-]*)-target$/.exec(attrName);
@@ -1027,7 +1039,7 @@ function defaultEventFor(host) {
1027
1039
  }
1028
1040
  function actionDescriptors(dataActionValue, host) {
1029
1041
  const descriptors = [];
1030
- for (const descriptor of dataActionValue.split(/\s+/)) {
1042
+ for (const { name: descriptor, start } of attributeTokens(dataActionValue)) {
1031
1043
  const hash = descriptor.indexOf("#");
1032
1044
  if (hash === -1) continue;
1033
1045
  let lhs = descriptor.slice(0, hash);
@@ -1043,7 +1055,14 @@ function actionDescriptors(dataActionValue, host) {
1043
1055
  }
1044
1056
  if (!lhs.startsWith(NAMESPACE_PREFIX)) continue;
1045
1057
  const method = /^[a-zA-Z_$][\w$]*/.exec(descriptor.slice(hash + 1))?.[0] ?? "";
1046
- descriptors.push({ identifier: lhs, method, eventType });
1058
+ descriptors.push({
1059
+ identifier: lhs,
1060
+ identifierStart: start + (arrow === -1 ? 0 : arrow + 2),
1061
+ method,
1062
+ methodStart: start + hash + 1,
1063
+ eventType,
1064
+ eventStart: start
1065
+ });
1047
1066
  }
1048
1067
  return descriptors;
1049
1068
  }
@@ -1059,9 +1078,11 @@ var DIAGNOSTIC_CODES = [
1059
1078
  "invalid-value",
1060
1079
  "unknown-action-controller",
1061
1080
  "unknown-action-method",
1081
+ "unknown-action-event",
1062
1082
  "orphan-target",
1063
1083
  "missing-required-target",
1064
1084
  "missing-conditional-target",
1085
+ "invalid-template-root",
1065
1086
  "missing-required-action",
1066
1087
  "missing-action-completion",
1067
1088
  "missing-action-event",
@@ -1077,11 +1098,14 @@ var DIAGNOSTIC_CODES = [
1077
1098
  "cardinality-violation",
1078
1099
  "forbidden-aria",
1079
1100
  "missing-announcer",
1101
+ "missing-action-param",
1102
+ "invalid-action-param",
1103
+ "confusable-action-param",
1080
1104
  "unknown-ignore-code"
1081
1105
  ];
1082
1106
 
1083
1107
  // src/inspector/check.ts
1084
- function isInside(node, ancestor) {
1108
+ function isDescendantOf(node, ancestor) {
1085
1109
  for (let current = node.parent; current; current = current.parent) {
1086
1110
  if (current === ancestor) return true;
1087
1111
  }
@@ -1174,11 +1198,13 @@ function checkSource(source, manifest) {
1174
1198
  const unnamedTargets = [];
1175
1199
  const targetsUnreadable = (container, scope, identifier) => {
1176
1200
  for (const node of unresolved) {
1177
- if (isWithin(node, container) && findOwner(node, identifier) === scope) return true;
1201
+ if (isSelfOrDescendantOf(node, container) && findOwner(node, identifier) === scope)
1202
+ return true;
1178
1203
  }
1179
1204
  for (const { node, identifier: hidden } of unnamedTargets) {
1180
1205
  if (hidden !== identifier) continue;
1181
- if (isWithin(node, container) && findOwner(node, identifier) === scope) return true;
1206
+ if (isSelfOrDescendantOf(node, container) && findOwner(node, identifier) === scope)
1207
+ return true;
1182
1208
  }
1183
1209
  return false;
1184
1210
  };
@@ -1237,7 +1263,7 @@ function checkSource(source, manifest) {
1237
1263
  const nodes = targetNodes.get(scope)?.get(identifier)?.get(condition.target) ?? [];
1238
1264
  const container = condition.within === "scope" ? scope : element;
1239
1265
  let held = 0;
1240
- for (const node of nodes) if (isWithin(node, container)) held += 1;
1266
+ for (const node of nodes) if (isSelfOrDescendantOf(node, container)) held += 1;
1241
1267
  if (condition.min !== void 0 && held < condition.min) return false;
1242
1268
  if (condition.max !== void 0 && held > condition.max) return false;
1243
1269
  return true;
@@ -1274,9 +1300,9 @@ function checkSource(source, manifest) {
1274
1300
  const authoredValueIdentifiers = /* @__PURE__ */ new Set();
1275
1301
  for (const attr of node.attrs) {
1276
1302
  if (attr.name === IGNORE_ATTR) {
1277
- for (const token of attr.value.split(/\s+/).filter((t) => t.length > 0)) {
1278
- if (!DIAGNOSTIC_CODES.includes(token)) {
1279
- const best = nearestName(token, DIAGNOSTIC_CODES);
1303
+ for (const token of attributeTokens(attr.value)) {
1304
+ if (!DIAGNOSTIC_CODES.includes(token.name)) {
1305
+ const best = nearestName(token.name, DIAGNOSTIC_CODES);
1280
1306
  push(
1281
1307
  diagnostics,
1282
1308
  "unknown-ignore-code",
@@ -1291,7 +1317,7 @@ function checkSource(source, manifest) {
1291
1317
  continue;
1292
1318
  }
1293
1319
  if (attr.name === FRAGMENT_ATTR) {
1294
- const identifiers = attr.value.split(/\s+/).filter((token) => token.length > 0);
1320
+ const identifiers = attributeTokens(attr.value);
1295
1321
  if (identifiers.length === 0) {
1296
1322
  report(
1297
1323
  node,
@@ -1302,13 +1328,13 @@ function checkSource(source, manifest) {
1302
1328
  );
1303
1329
  }
1304
1330
  for (const identifier of identifiers) {
1305
- if (!(identifier in known)) {
1306
- const best = nearestName(identifier, knownIdentifiers);
1331
+ if (!(identifier.name in known)) {
1332
+ const best = nearestName(identifier.name, knownIdentifiers);
1307
1333
  report(
1308
1334
  node,
1309
1335
  "unknown-controller",
1310
1336
  "error",
1311
- `Fragment declaration references unknown Stimeo controller "${identifier}".`,
1337
+ `Fragment declaration references unknown Stimeo controller "${identifier.name}".`,
1312
1338
  attr,
1313
1339
  asDidYouMean(best),
1314
1340
  tokenFix(attr, identifier, best)
@@ -1318,7 +1344,8 @@ function checkSource(source, manifest) {
1318
1344
  continue;
1319
1345
  }
1320
1346
  if (attr.name === "data-controller") {
1321
- for (const identifier of controllerIdentifiers(attr.value)) {
1347
+ for (const token of controllerIdentifierTokens(attr.value)) {
1348
+ const identifier = token.name;
1322
1349
  if (identifier in known) {
1323
1350
  scopes.push({ node, identifier });
1324
1351
  } else {
@@ -1330,7 +1357,7 @@ function checkSource(source, manifest) {
1330
1357
  `Unknown Stimeo controller "${identifier}".`,
1331
1358
  attr,
1332
1359
  asDidYouMean(best),
1333
- tokenFix(attr, identifier, best)
1360
+ tokenFix(attr, token, best)
1334
1361
  );
1335
1362
  }
1336
1363
  }
@@ -1350,24 +1377,27 @@ function checkSource(source, manifest) {
1350
1377
  );
1351
1378
  continue;
1352
1379
  }
1353
- const targetName = isDynamicValue(attr) ? "" : attr.value.trim();
1354
- if (targetName.length > 0 && !controller.targets.includes(targetName)) {
1355
- const best = nearestName(targetName, controller.targets);
1380
+ const declared = isDynamicValue(attr) ? [] : attributeTokens(attr.value);
1381
+ for (const token of declared) {
1382
+ if (controller.targets.includes(token.name)) continue;
1383
+ const best = nearestName(token.name, controller.targets);
1356
1384
  report(
1357
1385
  node,
1358
1386
  "unknown-target",
1359
1387
  "error",
1360
- `Unknown target "${targetName}" for "${targetIdentifier}". Known targets: ${list(controller.targets)}.`,
1388
+ `Unknown target "${token.name}" for "${targetIdentifier}". Known targets: ${list(controller.targets)}.`,
1361
1389
  attr,
1362
1390
  asDidYouMean(best),
1363
- tokenFix(attr, targetName, best)
1391
+ tokenFix(attr, token, best)
1364
1392
  );
1365
1393
  }
1366
1394
  const owner = findOwner(node, targetIdentifier);
1367
1395
  if (owner) {
1368
- if (targetName.length > 0) {
1369
- recordPresence(owner, targetIdentifier, targetName);
1370
- recordTargetNode(owner, targetIdentifier, targetName, node);
1396
+ if (declared.length > 0) {
1397
+ for (const token of declared) {
1398
+ recordPresence(owner, targetIdentifier, token.name);
1399
+ recordTargetNode(owner, targetIdentifier, token.name, node);
1400
+ }
1371
1401
  } else if (isDynamicValue(attr)) {
1372
1402
  unnamedTargets.push({ node, identifier: targetIdentifier });
1373
1403
  }
@@ -1431,7 +1461,15 @@ function checkSource(source, manifest) {
1431
1461
  tag: node.tag,
1432
1462
  inputType: node.attrs.find((a) => a.name === "type")?.value
1433
1463
  };
1434
- for (const { identifier, method, eventType } of actionDescriptors(attr.value, host)) {
1464
+ const paramsChecked = /* @__PURE__ */ new Set();
1465
+ for (const {
1466
+ identifier,
1467
+ identifierStart,
1468
+ method,
1469
+ methodStart,
1470
+ eventType,
1471
+ eventStart
1472
+ } of actionDescriptors(attr.value, host)) {
1435
1473
  const controller = known[identifier];
1436
1474
  if (controller && method.length > 0) {
1437
1475
  const owner = findOwner(node, identifier);
@@ -1456,7 +1494,7 @@ function checkSource(source, manifest) {
1456
1494
  `Action references unknown Stimeo controller "${identifier}".`,
1457
1495
  attr,
1458
1496
  asDidYouMean(best),
1459
- tokenFix(attr, identifier, best)
1497
+ tokenFix(attr, { name: identifier, start: identifierStart }, best)
1460
1498
  );
1461
1499
  } else if (method.length > 0 && !controller.actions.includes(method)) {
1462
1500
  const best = nearestName(method, controller.actions);
@@ -1467,12 +1505,124 @@ function checkSource(source, manifest) {
1467
1505
  `Unknown action "${method}" for "${identifier}". Known actions: ${list(controller.actions)}.`,
1468
1506
  attr,
1469
1507
  asDidYouMean(best),
1470
- tokenFix(attr, method, best)
1508
+ tokenFix(attr, { name: method, start: methodStart }, best)
1471
1509
  );
1472
1510
  }
1511
+ if (controller && method.length > 0 && !paramsChecked.has(`${identifier}#${method}`)) {
1512
+ paramsChecked.add(`${identifier}#${method}`);
1513
+ checkActionParams(node, attr, identifier, method, controller);
1514
+ }
1515
+ if (!isDynamicValue(attr)) {
1516
+ const emitted = /^(stimeo--[a-z0-9-]+):(.+)$/.exec(eventType);
1517
+ const source2 = emitted ? known[emitted[1]] : void 0;
1518
+ const name = emitted?.[2];
1519
+ if (source2 && name !== void 0 && !source2.events.includes(name)) {
1520
+ const best = nearestName(name, source2.events);
1521
+ report(
1522
+ node,
1523
+ "unknown-action-event",
1524
+ "error",
1525
+ `Unknown event "${name}" for "${emitted?.[1]}". Known events: ${list(source2.events)}.`,
1526
+ attr,
1527
+ asDidYouMean(best),
1528
+ tokenFix(attr, { name, start: eventStart + eventType.length - name.length }, best)
1529
+ );
1530
+ }
1531
+ }
1473
1532
  }
1474
1533
  }
1475
1534
  }
1535
+ function checkActionParams(element, action, identifier, method, controller) {
1536
+ const rules = controller.actionParams.filter((rule) => rule.action === method);
1537
+ if (rules.length === 0) return;
1538
+ const readable = !isDynamicValue(action) && element.origin === "markup" && !element.opaque;
1539
+ const expected = new Map(
1540
+ rules.map((rule) => [`data-${identifier}-${dasherize(rule.param)}-param`, rule])
1541
+ );
1542
+ for (const [attrName, rule] of expected) {
1543
+ const written = element.attrs.find((candidate) => candidate.name === attrName);
1544
+ if (!written) {
1545
+ if (!rule.required || !readable) continue;
1546
+ const confusable = confusableParamAttr(element, attrName, rule.param);
1547
+ report(
1548
+ element,
1549
+ "missing-action-param",
1550
+ "error",
1551
+ confusable ? `"${identifier}#${method}" reads its "${rule.param}" param, and "${confusable.name}" is not the attribute Stimulus builds it from.` : `"${identifier}#${method}" reads its "${rule.param}" param, which nothing on this element supplies.`,
1552
+ confusable ?? action,
1553
+ rule.suggestion
1554
+ );
1555
+ continue;
1556
+ }
1557
+ if (isDynamicValue(written)) continue;
1558
+ const value = written.value;
1559
+ if (value.length === 0) {
1560
+ if (!rule.required || !readable) continue;
1561
+ report(
1562
+ element,
1563
+ "missing-action-param",
1564
+ "error",
1565
+ `"${identifier}#${method}" reads its "${rule.param}" param, and "${attrName}" carries no value.`,
1566
+ written,
1567
+ rule.suggestion
1568
+ );
1569
+ continue;
1570
+ }
1571
+ if (rule.integer && !Number.isInteger(Number(value))) {
1572
+ report(
1573
+ element,
1574
+ "invalid-action-param",
1575
+ "error",
1576
+ `"${value}" is not an "${rule.param}" this action reads. It accepts a whole number.`,
1577
+ written,
1578
+ rule.suggestion
1579
+ );
1580
+ continue;
1581
+ }
1582
+ if (!rule.allowedValues || rule.allowedValues.includes(value)) continue;
1583
+ const best = nearestName(value, rule.allowedValues);
1584
+ report(
1585
+ element,
1586
+ "invalid-action-param",
1587
+ "error",
1588
+ `"${value}" is not a "${rule.param}" this action reads. It accepts ${list(rule.allowedValues)}.`,
1589
+ written,
1590
+ asDidYouMean(best) ?? rule.suggestion,
1591
+ best !== void 0 && written.valueStart !== void 0 ? {
1592
+ start: written.valueStart,
1593
+ end: written.valueStart + written.value.length,
1594
+ text: best,
1595
+ title: `Replace with "${best}"`
1596
+ } : void 0
1597
+ );
1598
+ }
1599
+ if (!readable) return;
1600
+ for (const candidate of element.attrs) {
1601
+ if (!candidate.name.startsWith(`data-${identifier}-`)) continue;
1602
+ if (expected.has(candidate.name)) continue;
1603
+ if (parseTargetAttr(candidate.name) || candidate.name.endsWith("-value")) continue;
1604
+ const best = [...expected.keys()].find((name) => namesTheParam(candidate.name, name));
1605
+ if (best === void 0) continue;
1606
+ report(
1607
+ element,
1608
+ "confusable-action-param",
1609
+ "warning",
1610
+ `"${candidate.name}" is not an attribute Stimulus reads. Action params are named "<param>-param".`,
1611
+ candidate,
1612
+ `Did you mean ${best}?`
1613
+ );
1614
+ }
1615
+ }
1616
+ function namesTheParam(written, attrName) {
1617
+ if (written === attrName) return false;
1618
+ return `${written}-param` === attrName || nearestName(written, [attrName]) !== void 0;
1619
+ }
1620
+ function confusableParamAttr(element, attrName, param) {
1621
+ const bare = `data-${dasherize(param)}`;
1622
+ return element.attrs.find(
1623
+ (candidate) => candidate.name === bare || namesTheParam(candidate.name, attrName)
1624
+ );
1625
+ }
1476
1626
  for (const identifier of authoredValueIdentifiers) {
1477
1627
  const controller = known[identifier];
1478
1628
  if (!controller) continue;
@@ -1532,19 +1682,30 @@ function checkSource(source, manifest) {
1532
1682
  const owners = nodesOf(rule.whenPresent);
1533
1683
  const hosts = rule.requireSameHost;
1534
1684
  const sharesHost = (target, selectors) => {
1535
- const ownerHosts = owners.map((owner) => nearestHost(owner, selectors));
1536
- if (ownerHosts.some((host) => !host)) return true;
1685
+ const hostOf = (el) => nearestHost(el, selectors);
1686
+ const ownerHosts = owners.map(hostOf).filter((host) => host !== null && host !== void 0);
1537
1687
  const candidates = nodesOf(target);
1538
- if (candidates.length === 0) return false;
1539
- return candidates.some((el) => {
1540
- const host = nearestHost(el, selectors);
1541
- return host ? ownerHosts.includes(host) : true;
1542
- });
1688
+ return ownerHosts.every(
1689
+ (ownerHost) => candidates.some((el) => {
1690
+ const host = hostOf(el);
1691
+ if (host === null) return false;
1692
+ return host ? host === ownerHost : true;
1693
+ })
1694
+ );
1695
+ };
1696
+ const sharesTargetHost = (target, hostTarget) => {
1697
+ const hostNodes = nodesOf(hostTarget);
1698
+ const hostOf = (el) => hostNodes.find((host) => isDescendantOf(el, host)) ?? null;
1699
+ const ownerHosts = owners.map(hostOf).filter((host) => host !== null);
1700
+ const candidates = nodesOf(target);
1701
+ return ownerHosts.every((ownerHost) => candidates.some((el) => hostOf(el) === ownerHost));
1543
1702
  };
1544
1703
  const satisfied = (target) => {
1704
+ const hostTarget = rule.requireSameTargetHost;
1705
+ if (hostTarget) return sharesTargetHost(target, hostTarget);
1545
1706
  if (hosts) return sharesHost(target, hosts);
1546
1707
  if (rule.requireInside)
1547
- return nodesOf(target).some((el) => owners.some((owner) => isInside(el, owner)));
1708
+ return nodesOf(target).some((el) => owners.some((owner) => isDescendantOf(el, owner)));
1548
1709
  return present.has(target);
1549
1710
  };
1550
1711
  const missing = rule.require.filter((target) => !satisfied(target));
@@ -1553,12 +1714,62 @@ function checkSource(source, manifest) {
1553
1714
  node,
1554
1715
  "missing-conditional-target",
1555
1716
  complete ? "error" : "warning",
1556
- hosts ? `"${identifier}" requires ${list(missing)} in the same ${rule.hostLabel ?? "element"} as its "${rule.whenPresent}".` : rule.requireInside ? `"${identifier}" requires ${list(missing)} inside its "${rule.whenPresent}".` : `"${identifier}" has a "${rule.whenPresent}" target, which also requires ${list(missing)}.`,
1717
+ rule.requireSameTargetHost ? `"${identifier}" requires ${list(missing)} in the same "${rule.requireSameTargetHost}" as its "${rule.whenPresent}".` : hosts ? `"${identifier}" requires ${list(missing)} in the same ${rule.hostLabel ?? "element"} as its "${rule.whenPresent}".` : rule.requireInside ? `"${identifier}" requires ${list(missing)} inside its "${rule.whenPresent}".` : `"${identifier}" has a "${rule.whenPresent}" target, which also requires ${list(missing)}.`,
1557
1718
  node,
1558
1719
  complete ? rule.suggestion : UNRESOLVED_TARGET_HINT
1559
1720
  );
1560
1721
  }
1561
1722
  }
1723
+ for (const { node, identifier } of scopes) {
1724
+ const controller = known[identifier];
1725
+ if (!controller) continue;
1726
+ const complete = scopeIsComplete(node, node, identifier);
1727
+ const nodesOf = (target) => targetNodes.get(node)?.get(identifier)?.get(target) ?? [];
1728
+ const hint = complete ? void 0 : UNRESOLVED_TARGET_HINT;
1729
+ for (const rule of controller.templateRoots) {
1730
+ for (const template of nodesOf(rule.template)) {
1731
+ if (template.origin === "markup" && template.tag !== "template") {
1732
+ report(
1733
+ node,
1734
+ "invalid-template-root",
1735
+ complete ? "error" : "warning",
1736
+ `"${identifier}" requires its "${rule.template}" to be a <template>, and it is a <${template.tag}>.`,
1737
+ template,
1738
+ hint ?? rule.suggestion
1739
+ );
1740
+ continue;
1741
+ }
1742
+ if (template.children.some((child) => child.origin === "erb")) continue;
1743
+ const rows = template.children;
1744
+ const row = rows[0];
1745
+ if (rows.length === 0) continue;
1746
+ if (rows.length !== 1 || !row) {
1747
+ report(
1748
+ node,
1749
+ "invalid-template-root",
1750
+ complete ? "error" : "warning",
1751
+ `"${identifier}" requires its "${rule.template}" to hold exactly one element, and it holds ${rows.length}.`,
1752
+ template,
1753
+ hint ?? rule.suggestion
1754
+ );
1755
+ continue;
1756
+ }
1757
+ if (!rule.rootTarget) continue;
1758
+ if (unnamedTargets.some((entry) => entry.node === row && entry.identifier === identifier)) {
1759
+ continue;
1760
+ }
1761
+ if (nodesOf(rule.rootTarget).includes(row)) continue;
1762
+ report(
1763
+ node,
1764
+ "invalid-template-root",
1765
+ complete ? "error" : "warning",
1766
+ `"${identifier}" requires the one element in its "${rule.template}" to be its "${rule.rootTarget}" itself.`,
1767
+ row,
1768
+ hint ?? rule.suggestion
1769
+ );
1770
+ }
1771
+ }
1772
+ }
1562
1773
  for (const { node, identifier } of scopes) {
1563
1774
  const controller = known[identifier];
1564
1775
  if (!controller) continue;
@@ -1809,7 +2020,7 @@ function checkSource(source, manifest) {
1809
2020
  if (rule.values && !rule.values.includes(value)) continue;
1810
2021
  if (findOwner(el, identifier) !== node) continue;
1811
2022
  const declaredAs = el.attrs.find((a) => a.name === targetAttrName);
1812
- if (declaredAs && !isDynamicValue(declaredAs) && declaredAs.value.trim() === rule.target) {
2023
+ if (declaredAs && !isDynamicValue(declaredAs) && attributeTokens(declaredAs.value).some((token) => token.name === rule.target)) {
1813
2024
  continue;
1814
2025
  }
1815
2026
  if (declaredAs && isDynamicValue(declaredAs)) continue;
@@ -1837,7 +2048,7 @@ function checkSource(source, manifest) {
1837
2048
  for (const container of containers) {
1838
2049
  const matched = [];
1839
2050
  for (const el of counted) {
1840
- if (!isWithin(el, container)) continue;
2051
+ if (!isSelfOrDescendantOf(el, container)) continue;
1841
2052
  if (rule.attr === void 0) {
1842
2053
  matched.push({ el, at: el });
1843
2054
  continue;
@@ -1893,14 +2104,14 @@ function checkSource(source, manifest) {
1893
2104
  for (const el of anchored) {
1894
2105
  for (const attr of el.attrs) {
1895
2106
  if (!IDREF_ATTRS.has(attr.name) || isDynamicValue(attr)) continue;
1896
- for (const token of attr.value.split(/\s+/).filter((t) => t.length > 0)) {
1897
- if (!ids.has(token)) {
1898
- const best = nearestName(token, [...ids]);
2107
+ for (const token of attributeTokens(attr.value)) {
2108
+ if (!ids.has(token.name)) {
2109
+ const best = nearestName(token.name, [...ids]);
1899
2110
  report(
1900
2111
  el,
1901
2112
  "unresolved-idref",
1902
2113
  "warning",
1903
- `${attr.name} references id "${token}", but no element in this file declares it.`,
2114
+ `${attr.name} references id "${token.name}", but no element in this file declares it.`,
1904
2115
  attr,
1905
2116
  asDidYouMean(best),
1906
2117
  tokenFix(attr, token, best)
@@ -2016,7 +2227,7 @@ function checkA11y(report, el, identifier, req, severity, isDynamicValue) {
2016
2227
  );
2017
2228
  }
2018
2229
  }
2019
- function isWithin(node, container) {
2230
+ function isSelfOrDescendantOf(node, container) {
2020
2231
  let current = node;
2021
2232
  while (current) {
2022
2233
  if (current === container) return true;
@@ -2121,15 +2332,13 @@ function push(out, code, severity, message, at, suggestion, fix) {
2121
2332
  });
2122
2333
  }
2123
2334
  function tokenFix(attr, token, replacement) {
2124
- if (replacement === void 0 || attr.valueStart === void 0 || token.length === 0) {
2335
+ if (replacement === void 0 || attr.valueStart === void 0 || token.name.length === 0) {
2125
2336
  return void 0;
2126
2337
  }
2127
- const index = attr.value.indexOf(token);
2128
- if (index < 0) return void 0;
2129
- const start = attr.valueStart + index;
2338
+ const start = attr.valueStart + token.start;
2130
2339
  return {
2131
2340
  start,
2132
- end: start + token.length,
2341
+ end: start + token.name.length,
2133
2342
  text: replacement,
2134
2343
  title: `Replace with "${replacement}"`
2135
2344
  };
@@ -2196,10 +2405,12 @@ var CONTROLLER_ARRAY_FIELDS = [
2196
2405
  "values",
2197
2406
  "valueConstraints",
2198
2407
  "valueRelations",
2408
+ "actionParams",
2199
2409
  "actions",
2200
2410
  "events",
2201
2411
  "requiredTargets",
2202
2412
  "conditionalTargets",
2413
+ "templateRoots",
2203
2414
  "requiredActions",
2204
2415
  "actionCompletion",
2205
2416
  "a11y",