vident 1.0.1 → 2.0.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 (80) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +54 -0
  3. data/README.md +49 -18
  4. data/lib/vident/caching.rb +4 -110
  5. data/lib/vident/capabilities/caching.rb +98 -0
  6. data/lib/vident/capabilities/child_element_rendering.rb +92 -0
  7. data/lib/vident/capabilities/class_list_building.rb +23 -0
  8. data/lib/vident/capabilities/declarable.rb +39 -0
  9. data/lib/vident/capabilities/identifiable.rb +54 -0
  10. data/lib/vident/capabilities/inspectable.rb +17 -0
  11. data/lib/vident/capabilities/root_element_rendering.rb +31 -0
  12. data/lib/vident/capabilities/stimulus_data_emitting.rb +98 -0
  13. data/lib/vident/capabilities/stimulus_declaring.rb +79 -0
  14. data/lib/vident/capabilities/stimulus_draft.rb +51 -0
  15. data/lib/vident/capabilities/stimulus_mutation.rb +60 -0
  16. data/lib/vident/capabilities/stimulus_parsing.rb +144 -0
  17. data/lib/vident/capabilities/tailwind.rb +18 -0
  18. data/lib/vident/component.rb +14 -76
  19. data/lib/vident/engine.rb +6 -5
  20. data/lib/vident/error.rb +16 -0
  21. data/lib/vident/internals/action_builder.rb +97 -0
  22. data/lib/vident/internals/attribute_writer.rb +17 -0
  23. data/lib/vident/internals/class_list_builder.rb +62 -0
  24. data/lib/vident/internals/declaration.rb +13 -0
  25. data/lib/vident/internals/declarations.rb +64 -0
  26. data/lib/vident/internals/draft.rb +47 -0
  27. data/lib/vident/internals/dsl.rb +172 -0
  28. data/lib/vident/internals/plan.rb +9 -0
  29. data/lib/vident/internals/registry.rb +37 -0
  30. data/lib/vident/internals/resolver.rb +316 -0
  31. data/lib/vident/internals/target_builder.rb +23 -0
  32. data/lib/vident/stable_id.rb +3 -3
  33. data/lib/vident/stimulus/action.rb +127 -0
  34. data/lib/vident/stimulus/base.rb +26 -0
  35. data/lib/vident/stimulus/class_map.rb +57 -0
  36. data/lib/vident/stimulus/collection.rb +40 -0
  37. data/lib/vident/stimulus/combinable.rb +30 -0
  38. data/lib/vident/stimulus/controller.rb +45 -0
  39. data/lib/vident/stimulus/naming.rb +9 -9
  40. data/lib/vident/stimulus/null.rb +7 -0
  41. data/lib/vident/stimulus/outlet.rb +93 -0
  42. data/lib/vident/stimulus/param.rb +56 -0
  43. data/lib/vident/stimulus/target.rb +48 -0
  44. data/lib/vident/stimulus/value.rb +57 -0
  45. data/lib/vident/stimulus_null.rb +4 -8
  46. data/lib/vident/tailwind.rb +4 -17
  47. data/lib/vident/types.rb +28 -0
  48. data/lib/vident/version.rb +1 -6
  49. data/lib/vident.rb +44 -36
  50. data/skills/vident/SKILL.md +133 -21
  51. data/skills/vident/api-reference.md +662 -0
  52. data/skills/vident/examples.md +505 -0
  53. metadata +40 -28
  54. data/lib/vident/child_element_helper.rb +0 -64
  55. data/lib/vident/class_list_builder.rb +0 -112
  56. data/lib/vident/component_attribute_resolver.rb +0 -87
  57. data/lib/vident/component_class_lists.rb +0 -34
  58. data/lib/vident/stimulus/primitive.rb +0 -38
  59. data/lib/vident/stimulus.rb +0 -31
  60. data/lib/vident/stimulus_action.rb +0 -133
  61. data/lib/vident/stimulus_action_collection.rb +0 -11
  62. data/lib/vident/stimulus_attribute_base.rb +0 -67
  63. data/lib/vident/stimulus_attributes.rb +0 -129
  64. data/lib/vident/stimulus_builder.rb +0 -119
  65. data/lib/vident/stimulus_class.rb +0 -59
  66. data/lib/vident/stimulus_class_collection.rb +0 -11
  67. data/lib/vident/stimulus_collection_base.rb +0 -51
  68. data/lib/vident/stimulus_component.rb +0 -75
  69. data/lib/vident/stimulus_controller.rb +0 -41
  70. data/lib/vident/stimulus_controller_collection.rb +0 -14
  71. data/lib/vident/stimulus_data_attribute_builder.rb +0 -32
  72. data/lib/vident/stimulus_helper.rb +0 -66
  73. data/lib/vident/stimulus_outlet.rb +0 -90
  74. data/lib/vident/stimulus_outlet_collection.rb +0 -11
  75. data/lib/vident/stimulus_param.rb +0 -42
  76. data/lib/vident/stimulus_param_collection.rb +0 -11
  77. data/lib/vident/stimulus_target.rb +0 -47
  78. data/lib/vident/stimulus_target_collection.rb +0 -18
  79. data/lib/vident/stimulus_value.rb +0 -39
  80. data/lib/vident/stimulus_value_collection.rb +0 -11
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  name: Vident
3
3
  description: This skill should be used when writing or editing Rails view components in a project that depends on `vident`, `vident-view_component`, or `vident-phlex` — i.e. any class inheriting from `Vident::ViewComponent::Base` or `Vident::Phlex::HTML`, any paired `*_component_controller.js` Stimulus file next to such a component, or the `stimulus_*` props / `stimulus do ... end` DSL / `child_element` / `root_element` / `class_list_for_stimulus_classes` / `Vident::StimulusNull` / `Vident::StableId` APIs. It also covers the `bin/rails generate vident:install` initializer and the per-request ID seeding it installs on `ApplicationController`.
4
- version: 0.1.0
4
+ version: 0.2.0
5
5
  ---
6
6
 
7
7
  # Vident
@@ -10,6 +10,8 @@ Vident is a thin layer on top of ViewComponent / Phlex that gives a component th
10
10
 
11
11
  A Vident component is always a class with props, a single `root_element`, and (optionally) a `stimulus do ... end` block that declares the controllers, actions, targets, values, classes and outlets its paired JavaScript file needs.
12
12
 
13
+ > **Going deeper.** This file is the everyday reference. For end-to-end walkthroughs (dashboard, forms, slot-based parent/child wiring, ERB helper comparisons), read [`examples.md`](examples.md). For the exhaustive public-API spec (every signature, raise-condition, and argument shape), read [`api-reference.md`](api-reference.md).
14
+
13
15
  ---
14
16
 
15
17
  ## 1. Stimulus → Vident mapping
@@ -52,13 +54,64 @@ class Foo::BarComponent < Vident::ViewComponent::Base
52
54
  end
53
55
  ```
54
56
 
57
+ **Subclass re-enables the controller.** `no_stimulus_controller` is inherited by subclasses. A subclass that has its own paired JS controller calls `has_stimulus_controller` to flip the flag back on:
58
+
59
+ ```ruby
60
+ class ApplicationComponent < Vident::Phlex::HTML
61
+ no_stimulus_controller # shell — no paired JS
62
+ end
63
+
64
+ class DropdownComponent < ApplicationComponent
65
+ has_stimulus_controller # emits data-controller="dropdown-component"
66
+ stimulus { actions :toggle }
67
+ end
68
+ ```
69
+
55
70
  Cross-controller references elsewhere (actions/targets/values/classes/outlets) use the `"path/to/controller"` **string** form — Vident stimulizes it for you.
56
71
 
57
72
  ### 1.2 Actions
58
73
 
59
74
  Stimulus descriptor: `event->controller#method`, with optional modifiers (`:once`, `:prevent`, `keydown.ctrl+a`, `@window`, etc.). Stimulus encodes them as space-separated tokens in `data-action="..."`.
60
75
 
61
- Vident `actions` DSL entries (all of these work inside `stimulus do ... end`):
76
+ **Primary form the fluent `action(...)` builder.** Singular `action` returns a builder that reads left-to-right:
77
+
78
+ ```ruby
79
+ stimulus do
80
+ action :click # implied#click
81
+ action(:submit).on(:click) # click->implied#submit
82
+ action(:save).on(:click).modifier(:prevent, :stop) # click:prevent:stop->implied#save
83
+ action(:escape).on(:keydown).keyboard("esc").window # keydown.esc@window->implied#escape
84
+ action(:delete).when { admin? } # conditional — `.when` takes a predicate proc
85
+ end
86
+ ```
87
+
88
+ Chain methods: `.on(event)`, `.call_method(name)` (override), `.modifier(*opts)`, `.keyboard(str)`, `.window`, `.on_controller(alias_sym)`, `.when { predicate }`. Each returns `self`.
89
+
90
+ **Kwargs shorthand.** Equivalent to the fluent chain — pick whichever reads better:
91
+
92
+ ```ruby
93
+ action :save, on: :click, modifier: [:prevent, :stop]
94
+ action :escape, on: :keydown, keyboard: "esc", window: true
95
+ action :delete, when: -> { admin? }
96
+ action :save, on: :click, call_method: :handle_save
97
+ ```
98
+
99
+ Recognised keys: `on:`, `call_method:`, `modifier:` (Symbol or Array), `keyboard:`, `window:`, `on_controller:`, `when:`. Anything else raises `ArgumentError`.
100
+
101
+ **Controller aliases.** Declare a short name for a cross-controller path with `controller "path", as: :alias`, then reference it from action entries:
102
+
103
+ ```ruby
104
+ stimulus do
105
+ controller "admin/users", as: :admin
106
+
107
+ action(:save).on(:click).on_controller(:admin) # click->admin--users#save
108
+ action :save, on: :click, on_controller: :admin # same, kwargs form
109
+ end
110
+ ```
111
+
112
+ The alias resolves at render time — unknown aliases raise `Vident::DeclarationError`. Also works for runtime inputs: `stimulus_actions: [{method: :save, controller: :admin}]` resolves against the same declared map.
113
+
114
+ **Legacy plural form.** Still accepted for compat — `actions(*entries)` accepts:
62
115
 
63
116
  | Ruby | Emits |
64
117
  | ------------------------------------------- | -------------------------------------------------- |
@@ -67,10 +120,9 @@ Vident `actions` DSL entries (all of these work inside `stimulus do ... end`):
67
120
  | `[:click, "other/ctrl", :my_thing]` | `click->other--ctrl#myThing` |
68
121
  | `"click->other--ctrl#myThing"` | pass-through, parsed into its parts |
69
122
  | `{event: :click, method: :submit, options: [:once, :prevent]}` | `click:once:prevent->implied#submit` |
70
- | `Vident::StimulusAction::Descriptor.new(event: :click, method: :submit, options: [:once])` | same — typed data object, Hash is sugar |
71
123
  | `-> { [:click, :my_thing] if @editable }` | proc, evaluated in component instance; `nil`/`false` returns drop the entry |
72
124
 
73
- **Modifiers via the Hash / Descriptor form.** Accepted keys on the hash (and the `Descriptor` data class):
125
+ **Modifiers via the Hash form.** Accepted keys:
74
126
 
75
127
  | Key | Type | Emits |
76
128
  | ------------ | ----------------- | ---------------------------------------- |
@@ -81,7 +133,7 @@ Vident `actions` DSL entries (all of these work inside `stimulus do ... end`):
81
133
  | `keyboard:` | String like `"ctrl+a"` | `.ctrl+a` suffix on event filter |
82
134
  | `window:` | Boolean | `@window` suffix on event |
83
135
 
84
- Unknown option symbols raise `ArgumentError`. Use the Hash form for the common case; use `Vident::StimulusAction::Descriptor.new(...)` when you want a typed, passable value object (reusable across components, shared helpers).
136
+ Unknown option symbols raise `ArgumentError`. The Hash descriptor is parsed directly into `Vident::Stimulus::Action` there is no separate `Descriptor` class in V2.
85
137
 
86
138
  ```ruby
87
139
  actions({event: :keydown, method: :on_escape, keyboard: "esc", options: [:prevent]})
@@ -245,7 +297,7 @@ stimulus_outlets: [
245
297
  ]
246
298
  ```
247
299
 
248
- **(c) Child self-registers on a host via `stimulus_outlet_host:`.** Every Vident component inherits a `stimulus_outlet_host` prop. Passing a parent component at render time calls `host.add_stimulus_outlets(self)` in `prepare_stimulus_collections`, so the host's root gets the outlet attribute without enumerating children in its DSL:
300
+ **(c) Child self-registers on a host via `stimulus_outlet_host:`.** Every Vident component inherits a `stimulus_outlet_host` prop. Passing a parent component at render time calls `host.add_stimulus_outlets(self)` in `after_initialize` (via `Vident::Capabilities::StimulusDraft`), so the host's root gets the outlet attribute without enumerating children in its DSL:
249
301
 
250
302
  ```ruby
251
303
  render PageComponent.new do |page|
@@ -327,7 +379,7 @@ prop :count, Integer, default: 0 # with default
327
379
  prop :url, _Nilable(String) # optional / nilable
328
380
  prop :variant, _Union(:primary, :secondary), default: :primary
329
381
  prop :items, _Array(Hash), default: -> { [] } # callable defaults must be lambdas
330
- prop :open, _Boolean, default: false # generates an `open?` predicate
382
+ prop :open, _Boolean, default: false # pass `predicate: :public` to also get an `open?` method
331
383
  ```
332
384
 
333
385
  Props become `@ivar`s at init time. To also expose a reader method, declare the prop with `reader: :public`.
@@ -341,9 +393,9 @@ From `Vident::Component`:
341
393
  - `classes` — `String | Array(String)`. Appended to the root element's `class=`.
342
394
  - `html_options` — `Hash`. Merged onto the root element; highest precedence.
343
395
 
344
- From `Vident::StimulusComponent`:
396
+ From `Vident::Component`:
345
397
 
346
- - `stimulus_controllers` — `Array(String | Symbol | StimulusController | Collection)`. Defaults to `[default_controller_path]` unless `no_stimulus_controller` is declared.
398
+ - `stimulus_controllers` — `Array(String | Symbol | Vident::Stimulus::Controller)`. Defaults to `[default_controller_path]` unless `no_stimulus_controller` is declared.
347
399
  - `stimulus_actions`, `stimulus_targets`, `stimulus_values`, `stimulus_classes`, `stimulus_outlets` — Array / Hash props matching the shapes described in section 1.
348
400
  - `stimulus_outlet_host` — optional `Vident::Component`; activates child→host outlet self-registration.
349
401
 
@@ -411,15 +463,50 @@ When handwriting HTML inside ERB instead of using `child_element`, emit just the
411
463
  <div <%= component.as_stimulus_values(%i[count label]) %>></div>
412
464
  ```
413
465
 
414
- Plural (`as_stimulus_targets`, `as_stimulus_actions`, `as_stimulus_values`, `as_stimulus_classes`, `as_stimulus_outlets`, `as_stimulus_controllers`) and singular variants exist for every attribute kind. These helpers are defined on `Vident::ViewComponent::Base`; for Phlex, use `child_element` or compose directly.
466
+ Plural (`as_stimulus_targets`, `as_stimulus_actions`, `as_stimulus_values`, `as_stimulus_params`, `as_stimulus_classes`, `as_stimulus_outlets`, `as_stimulus_controllers`) and singular variants (`as_stimulus_target`, `as_stimulus_action`, `as_stimulus_value`, `as_stimulus_param`, `as_stimulus_class`, `as_stimulus_outlet`, `as_stimulus_controller`) exist for every attribute kind. These helpers are defined on `Vident::ViewComponent::Base`; for Phlex, use `child_element` or compose directly.
467
+
468
+ ### Class-level Stimulus builders (no instance needed)
469
+
470
+ When you need a Stimulus value without a component instance (Turbo-Stream partials, JSON endpoints, test selectors), call the builders on the class:
471
+
472
+ ```ruby
473
+ ButtonComponent.stimulus_target(:submit) # Vident::Stimulus::Target
474
+ ButtonComponent.stimulus_action(:click, :handle) # click->implied#handle
475
+ ButtonComponent.stimulus_value(:count, 0)
476
+ ButtonComponent.stimulus_param(:item_id, 42)
477
+ ButtonComponent.stimulus_class(:loading, "opacity-50")
478
+ ButtonComponent.stimulus_outlet(:modal, ".js-modal") # selector required
479
+ ButtonComponent.stimulus_controller # the implied controller
480
+ ```
481
+
482
+ Returns a `Vident::Stimulus::*` value object with the same `#to_h` / `#to_data_pair` as the instance equivalents — splat `.to_h` into a tag's HTML options. Two restrictions at class level: **outlets require an explicit selector** (no `component_id` to auto-scope), and **cross-controller forms are rejected** (call `Vident::Stimulus::Target.parse(...)` directly for those).
483
+
484
+ ### Rendering outside `root_element(...)`
485
+
486
+ For components that build their root tag via a third-party helper (e.g. `inline_svg_tag`), two instance methods return what `root_element(...)` would emit:
487
+
488
+ - `root_element_class_list(extra_classes = nil)` → `String` with the full class cascade (`component_name`, `root_element_classes`, `@classes` prop, `html_options[:class]`, extras) plus Tailwind-merging.
489
+ - `root_element_data_attributes` → `Hash` (Symbol keys) with the full `data-*` set (controller, action, target, value, param, class, outlet) from the sealed Plan.
490
+
491
+ ```ruby
492
+ def view_template
493
+ svg("data-src" => helpers.image_path(file_name),
494
+ id: @id,
495
+ class: root_element_class_list,
496
+ data: root_element_data_attributes) {}
497
+ end
498
+ ```
415
499
 
416
500
  ---
417
501
 
418
502
  ## 3. `stimulus do ... end` block
419
503
 
420
- Opens a `Vident::StimulusBuilder` instance scoped to the class. It supports `actions`, `targets`, `values`, `values_from_props`, `classes`, `outlets`. Multiple `stimulus do` blocks on the same class are merged; a subclass's block is merged with its superclass's (subclass entries appended, values/classes/outlets merged by key, subclass wins on conflicts).
504
+ Opens a `Vident::Internals::DSL` instance scoped to the class. It supports `actions`, `targets`, `values`, `values_from_props`, `classes`, `outlets`. Multiple `stimulus do` blocks on the same class are merged; a subclass's block is merged with its superclass's (subclass entries appended, values/classes/outlets merged by key, subclass wins on conflicts).
505
+
506
+ Procs passed anywhere in the DSL are evaluated via `instance_exec` on the **component instance** at render time (Phlex `before_template` / ViewComponent `before_render`), so they see `@ivars`, public/private instance methods, and the view context.
421
507
 
422
- Procs passed anywhere in the DSL are evaluated via `instance_exec` on the **component instance** at render time, so they see `@ivars` and public/private instance methods.
508
+ - **Phlex**: `helpers` is deprecated in phlex-rails. Opt in per Rails helper via `include Phlex::Rails::Helpers::NumberWithPrecision` (etc.), or use the `phlex_helpers :number_with_precision, :t, :l` class macro on `Vident::Phlex::HTML` which expands to the matching includes. Then call the helper bare inside the proc — `number_with_precision(@amount, precision: 2)`. See [phlex.fun/rails/helpers](https://www.phlex.fun/rails/helpers) for the full adapter list.
509
+ - **ViewComponent**: `helpers.<method>` and `view_context.<method>` both work.
423
510
 
424
511
  ---
425
512
 
@@ -490,8 +577,30 @@ Vident::StableId.with_sequence_generator(seed: "some-unique-key") { render ... }
490
577
 
491
578
  - **`after_component_initialize`** — override in your component; runs after props are assigned and Vident has prepared its stimulus collections. Don't override `after_initialize` unless you `super` — Literal calls it to wire everything up.
492
579
  - **`component_name` / `stimulus_identifier`** — class method and instance method; the kebab-case/`--`-separated identifier. Used for outlet auto-selectors, scoped event names, and the default class on the root.
493
- - **Caching** (`include Vident::Caching` + `with_cache_key :attr1, :attr2`) — declares attributes that feed `cache_key`. Combined with a template mtime so edits bust the cache. `depends_on(OtherComponent, …)` chains subcomponent mtimes into the key.
494
- - **`clone(overrides = {})`** returns a new instance with merged props.
580
+ - **Caching** (`include Vident::Caching` + `with_cache_key :attr1, :attr2`) — declares attributes that feed `cache_key`. Combined with a template mtime so edits bust the cache. `depends_on(OtherComponent, …)` chains subcomponent mtimes into the key. Two separable concerns:
581
+ - **Computing the key** — `component.cache_key` is always available once `with_cache_key` is declared. Use it for etags, conditional rendering, explicit `Rails.cache.fetch(key) { ... }` at the call site, or any other place you need a content-addressed identifier.
582
+ - **Fragment-caching the render** — `cache_component(*extra_keys, &block)` wraps the block with Rails.cache using the Vident-computed key. Works on both adapters. For Phlex, call it inside `view_template` (delegates to Phlex's `cache(...)`); for ViewComponent, call inside `call` (uses `Rails.cache.fetch` + `capture`). Sidecar ERB templates can just write `<% cache cache_key do %> ... <% end %>` directly.
583
+
584
+ ```ruby
585
+ # Phlex
586
+ def view_template
587
+ cache_component do
588
+ root_element { ... }
589
+ end
590
+ end
591
+
592
+ # ViewComponent (def call form)
593
+ def call
594
+ cache_component { root_element { ... } }
595
+ end
596
+
597
+ # ViewComponent (sidecar ERB) — use the Rails helper with component.cache_key
598
+ # <% cache cache_key do %>
599
+ # <%= root_element do %>...<% end %>
600
+ # <% end %>
601
+ ```
602
+ Calling `cache_component` on a non-cacheable component (no `with_cache_key`) raises `Vident::ConfigurationError`.
603
+ - **`with(overrides = {})`** — returns a new instance with merged props. (`clone` is a backward-compat alias.)
495
604
  - **Phlex tag safety** — `Vident::Phlex::HTML` validates every `child_element` tag name against a whitelist; passing an unknown tag raises.
496
605
 
497
606
  ---
@@ -553,6 +662,8 @@ Inside `<name>OutletConnected`, **do not iterate `this.<name>Outlets`**. Stimulu
553
662
 
554
663
  ## 8. Recipes
555
664
 
665
+ One-liners per task. For worked end-to-end versions (dashboard with outlets, slot trigger, ERB variants) see [`examples.md`](examples.md).
666
+
556
667
  **Click handler on the root** — `stimulus do; actions [:click, :select]; end` + `select(event) {…}` in JS.
557
668
 
558
669
  **Click handler on a child button** — `card.child_element(:button, stimulus_action: [:click, :promote]) { "Promote" }`.
@@ -616,13 +727,14 @@ end
616
727
 
617
728
  ## 9. Key source files
618
729
 
619
- - `lib/vident/stimulus_builder.rb` DSL evaluator.
620
- - `lib/vident/stimulus_attributes.rb` — parser for every `stimulus_*` input shape + `as_stimulus_*` helpers' backing.
621
- - `lib/vident/stimulus_{action,target,value,outlet,class,controller}.rb` — value objects; read `parse_arguments` to learn the argument shapes.
622
- - `lib/vident/child_element_helper.rb` — `child_element` kwargs and validation.
623
- - `lib/vident/component_attribute_resolver.rb` — how DSL, props, and `root_element_attributes` compose at render time.
624
- - `lib/vident/component_class_lists.rb` — `class_list_for_stimulus_classes` / `render_classes`.
730
+ For the exhaustive public-API listing (every method signature, argument shape, and raise-condition, verified against current code), see [`api-reference.md`](api-reference.md). The files below are useful when you need to read the implementation itself.
731
+
732
+ - `lib/vident/component.rb` — composition root; includes all capabilities in dependency order.
625
733
  - `lib/vident/stable_id.rb` — the StableId strategy system.
626
734
  - `lib/vident/stimulus_null.rb` — the StimulusNull sentinel.
627
- - `lib/vident/view_component/base.rb` / `lib/vident/phlex/html.rb` framework-specific `root_element` / `child_element` backings and (ViewComponent only) `as_stimulus_*` helpers.
735
+ - `lib/vident/stimulus/` value classes: `Action`, `Target`, `Controller`, `Outlet`, `Value`, `Param`, `ClassMap`, `Collection`, `Null`, `Naming`.
736
+ - `lib/vident/capabilities/` — focused capability mixins: `Tailwind`, `Caching`, `Declarable`, `Identifiable`, `StimulusDeclaring`, `StimulusParsing`, `StimulusMutation`, `StimulusDraft`, `StimulusDataEmitting`, `ClassListBuilding`, `RootElementRendering`, `ChildElementRendering`, `Inspectable`.
737
+ - `lib/vident/internals/` — internal DSL/resolver plumbing: `Registry`, `Declaration`, `Declarations`, `DSL`, `Draft`, `Plan`, `Resolver`, `AttributeWriter`, `ClassListBuilder`, `ActionBuilder`, `TargetBuilder`.
738
+ - `lib/vident/phlex/html.rb` — Phlex adapter (`root_element`, `child_element`, tag whitelist).
739
+ - `lib/vident/view_component/base.rb` — ViewComponent adapter (`root_element`, `child_element`, `as_stimulus_*` helpers).
628
740
  - `test/dummy/app/components/dashboard/` — canonical multi-component example (outlets, scoped events, `StimulusNull`, dynamic classes, `values_from_props`, `class_list_for_stimulus_classes`, full JS side).