vident 1.0.2 → 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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +43 -0
- data/README.md +45 -17
- data/lib/vident/caching.rb +4 -110
- data/lib/vident/capabilities/caching.rb +98 -0
- data/lib/vident/capabilities/child_element_rendering.rb +92 -0
- data/lib/vident/capabilities/class_list_building.rb +23 -0
- data/lib/vident/capabilities/declarable.rb +39 -0
- data/lib/vident/capabilities/identifiable.rb +54 -0
- data/lib/vident/capabilities/inspectable.rb +17 -0
- data/lib/vident/capabilities/root_element_rendering.rb +31 -0
- data/lib/vident/capabilities/stimulus_data_emitting.rb +98 -0
- data/lib/vident/capabilities/stimulus_declaring.rb +79 -0
- data/lib/vident/capabilities/stimulus_draft.rb +51 -0
- data/lib/vident/capabilities/stimulus_mutation.rb +60 -0
- data/lib/vident/capabilities/stimulus_parsing.rb +144 -0
- data/lib/vident/capabilities/tailwind.rb +18 -0
- data/lib/vident/component.rb +14 -76
- data/lib/vident/engine.rb +6 -5
- data/lib/vident/error.rb +16 -0
- data/lib/{vident2 → vident}/internals/action_builder.rb +18 -22
- data/lib/vident/internals/attribute_writer.rb +17 -0
- data/lib/{vident2 → vident}/internals/class_list_builder.rb +5 -22
- data/lib/vident/internals/declaration.rb +13 -0
- data/lib/{vident2 → vident}/internals/declarations.rb +6 -18
- data/lib/{vident2 → vident}/internals/draft.rb +3 -16
- data/lib/{vident2 → vident}/internals/dsl.rb +6 -32
- data/lib/vident/internals/plan.rb +9 -0
- data/lib/vident/internals/registry.rb +37 -0
- data/lib/{vident2 → vident}/internals/resolver.rb +101 -91
- data/lib/{vident2 → vident}/internals/target_builder.rb +1 -7
- data/lib/vident/stable_id.rb +3 -3
- data/lib/{vident2 → vident}/stimulus/action.rb +11 -24
- data/lib/vident/stimulus/base.rb +26 -0
- data/lib/{vident2 → vident}/stimulus/class_map.rb +6 -18
- data/lib/{vident2 → vident}/stimulus/collection.rb +6 -8
- data/lib/vident/stimulus/combinable.rb +30 -0
- data/lib/vident/stimulus/controller.rb +45 -0
- data/lib/vident/stimulus/naming.rb +9 -9
- data/lib/vident/stimulus/null.rb +7 -0
- data/lib/{vident2 → vident}/stimulus/outlet.rb +12 -32
- data/lib/{vident2 → vident}/stimulus/param.rb +5 -11
- data/lib/{vident2 → vident}/stimulus/target.rb +5 -14
- data/lib/vident/stimulus/value.rb +57 -0
- data/lib/vident/stimulus_null.rb +4 -8
- data/lib/vident/tailwind.rb +4 -17
- data/lib/vident/types.rb +28 -0
- data/lib/vident/version.rb +1 -6
- data/lib/vident.rb +44 -36
- data/skills/vident/SKILL.md +122 -19
- data/skills/vident/api-reference.md +259 -115
- data/skills/vident/examples.md +23 -10
- metadata +38 -60
- data/lib/vident/child_element_helper.rb +0 -64
- data/lib/vident/class_list_builder.rb +0 -112
- data/lib/vident/component_attribute_resolver.rb +0 -106
- data/lib/vident/component_class_lists.rb +0 -37
- data/lib/vident/stimulus/primitive.rb +0 -38
- data/lib/vident/stimulus.rb +0 -31
- data/lib/vident/stimulus_action.rb +0 -133
- data/lib/vident/stimulus_action_collection.rb +0 -11
- data/lib/vident/stimulus_attribute_base.rb +0 -67
- data/lib/vident/stimulus_attributes.rb +0 -129
- data/lib/vident/stimulus_builder.rb +0 -136
- data/lib/vident/stimulus_class.rb +0 -59
- data/lib/vident/stimulus_class_collection.rb +0 -11
- data/lib/vident/stimulus_collection_base.rb +0 -51
- data/lib/vident/stimulus_component.rb +0 -75
- data/lib/vident/stimulus_controller.rb +0 -41
- data/lib/vident/stimulus_controller_collection.rb +0 -14
- data/lib/vident/stimulus_data_attribute_builder.rb +0 -32
- data/lib/vident/stimulus_helper.rb +0 -66
- data/lib/vident/stimulus_outlet.rb +0 -90
- data/lib/vident/stimulus_outlet_collection.rb +0 -11
- data/lib/vident/stimulus_param.rb +0 -42
- data/lib/vident/stimulus_param_collection.rb +0 -11
- data/lib/vident/stimulus_target.rb +0 -47
- data/lib/vident/stimulus_target_collection.rb +0 -18
- data/lib/vident/stimulus_value.rb +0 -39
- data/lib/vident/stimulus_value_collection.rb +0 -11
- data/lib/vident2/caching.rb +0 -93
- data/lib/vident2/component.rb +0 -538
- data/lib/vident2/engine.rb +0 -18
- data/lib/vident2/error.rb +0 -30
- data/lib/vident2/internals/attribute_writer.rb +0 -22
- data/lib/vident2/internals/declaration.rb +0 -17
- data/lib/vident2/internals/plan.rb +0 -12
- data/lib/vident2/internals/registry.rb +0 -41
- data/lib/vident2/phlex/html.rb +0 -84
- data/lib/vident2/phlex.rb +0 -9
- data/lib/vident2/stimulus/controller.rb +0 -59
- data/lib/vident2/stimulus/naming.rb +0 -26
- data/lib/vident2/stimulus/null.rb +0 -16
- data/lib/vident2/stimulus/value.rb +0 -77
- data/lib/vident2/tailwind.rb +0 -19
- data/lib/vident2/version.rb +0 -5
- data/lib/vident2/view_component/base.rb +0 -124
- data/lib/vident2/view_component.rb +0 -9
- data/lib/vident2.rb +0 -50
|
@@ -72,7 +72,7 @@ Public instance methods:
|
|
|
72
72
|
`:element_tag` (Symbol), `:html_options` (Hash), `:id` (String), `:classes`
|
|
73
73
|
(String | Array), and any of the seven `stimulus_<plural>:` / `stimulus_<singular>:`
|
|
74
74
|
keys documented in section 5.
|
|
75
|
-
- `
|
|
75
|
+
- `with(overrides = {})` — returns a new instance, `self.class.new(**to_h.merge(overrides))`. `clone(overrides = {})` is a backward-compat alias.
|
|
76
76
|
- `inspect(klass_name = "Component")` — formatted debug string with every prop.
|
|
77
77
|
- `id` — `String`, auto-generated from `StableId` if `@id` was nil. The generated form
|
|
78
78
|
is `"#{component_name}-#{StableId.next_id_in_sequence}"`.
|
|
@@ -96,18 +96,36 @@ From `Vident::Component` (`lib/vident/component.rb`):
|
|
|
96
96
|
| `classes` | `_Union(String, _Array(String))` | `[]` | Appended on top of all other class sources. |
|
|
97
97
|
| `html_options` | `Hash` | `{}` | Merged onto root; highest class-source precedence. |
|
|
98
98
|
|
|
99
|
-
From `Vident::
|
|
99
|
+
From `Vident::Component` via the `StimulusDeclaring` / `StimulusParsing` capability mixins:
|
|
100
100
|
|
|
101
|
-
| Prop | Type
|
|
102
|
-
| ----------------------- |
|
|
103
|
-
| `stimulus_controllers` | `
|
|
104
|
-
| `stimulus_actions` | `
|
|
105
|
-
| `stimulus_targets` | `
|
|
106
|
-
| `stimulus_outlets` | `
|
|
107
|
-
| `stimulus_outlet_host` | `_Nilable(Vident::Component)`
|
|
108
|
-
| `stimulus_values` | `
|
|
109
|
-
| `stimulus_params` | `
|
|
110
|
-
| `stimulus_classes` | `
|
|
101
|
+
| Prop | Type | Default |
|
|
102
|
+
| ----------------------- | --------------------------------- | ------------------------------------ |
|
|
103
|
+
| `stimulus_controllers` | `Vident::Types::StimulusControllers` | `[default_controller_path]` unless `no_stimulus_controller`, else `[]` |
|
|
104
|
+
| `stimulus_actions` | `Vident::Types::StimulusActions` | `[]` |
|
|
105
|
+
| `stimulus_targets` | `Vident::Types::StimulusTargets` | `[]` |
|
|
106
|
+
| `stimulus_outlets` | `Vident::Types::StimulusOutlets` | `[]` |
|
|
107
|
+
| `stimulus_outlet_host` | `_Nilable(Vident::Component)` | `nil` |
|
|
108
|
+
| `stimulus_values` | `Vident::Types::StimulusValues` | `{}` |
|
|
109
|
+
| `stimulus_params` | `Vident::Types::StimulusParams` | `{}` |
|
|
110
|
+
| `stimulus_classes` | `Vident::Types::StimulusClasses` | `{}` |
|
|
111
|
+
|
|
112
|
+
`Vident::Types::*` are the canonical Literal type unions for each prop kind (file: `lib/vident/types.rb`). The unions are:
|
|
113
|
+
|
|
114
|
+
- `StimulusControllers` → `_Array(_Union(String, Symbol, Vident::Stimulus::Controller))`
|
|
115
|
+
- `StimulusActions` → `_Array(_Union(String, Symbol, Array, Hash, Vident::Stimulus::Action))`
|
|
116
|
+
- `StimulusTargets` → `_Array(_Union(String, Symbol, Array, Vident::Stimulus::Target))`
|
|
117
|
+
- `StimulusOutlets` → `_Array(_Union(String, Symbol, Array, Vident::Stimulus::Outlet))`
|
|
118
|
+
- `StimulusValues` → `_Union(_Hash(Symbol, _Any), Array, Vident::Stimulus::Value)`
|
|
119
|
+
- `StimulusParams` → `_Union(_Hash(Symbol, _Any), Array, Vident::Stimulus::Param)`
|
|
120
|
+
- `StimulusClasses` → `_Union(_Hash(Symbol, _Any), Array, Vident::Stimulus::ClassMap)`
|
|
121
|
+
|
|
122
|
+
Exposed publicly so user components can reuse them when adding matching props:
|
|
123
|
+
|
|
124
|
+
```ruby
|
|
125
|
+
class MyComponent < Vident::ViewComponent::Base
|
|
126
|
+
prop :extra_actions, Vident::Types::StimulusActions, default: -> { [] }
|
|
127
|
+
end
|
|
128
|
+
```
|
|
111
129
|
|
|
112
130
|
---
|
|
113
131
|
|
|
@@ -120,9 +138,12 @@ All of these live on `Vident::Component`'s class body (via included modules).
|
|
|
120
138
|
or an immediate value; callable is required when the default is non-frozen (hash, array).
|
|
121
139
|
- `no_stimulus_controller` — sets a class ivar that drops the implied controller from
|
|
122
140
|
the `stimulus_controllers` default. Use when the component is purely presentational
|
|
123
|
-
and needs no paired `_controller.js`.
|
|
141
|
+
and needs no paired `_controller.js`. Inherited by subclasses.
|
|
142
|
+
- `has_stimulus_controller` — the inverse: re-enables the implied controller on a
|
|
143
|
+
subclass whose parent declared `no_stimulus_controller`. Idempotent; order relative
|
|
144
|
+
to `stimulus do` blocks does not matter.
|
|
124
145
|
- `stimulus_controller?` — `Boolean`, `true` by default; becomes `false` after a
|
|
125
|
-
`no_stimulus_controller` declaration
|
|
146
|
+
`no_stimulus_controller` declaration and `true` again after `has_stimulus_controller`.
|
|
126
147
|
- `stimulus_identifier_path` — the `name.underscore` of the class (e.g.
|
|
127
148
|
`"dashboard/release_card_component"`). Falls back to `"anonymous_component"` for
|
|
128
149
|
anonymous classes.
|
|
@@ -136,84 +157,149 @@ All of these live on `Vident::Component`'s class body (via included modules).
|
|
|
136
157
|
`:"foo-component:dataReady"`. Also an instance method.
|
|
137
158
|
- `stimulus_scoped_event_on_window(event)` — same, with `@window` suffix. Also an
|
|
138
159
|
instance method.
|
|
139
|
-
- `stimulus(&block)` — the DSL entry point. Opens a `Vident::
|
|
160
|
+
- `stimulus(&block)` — the DSL entry point. Opens a `Vident::Internals::DSL` block
|
|
140
161
|
evaluator. See section 3.
|
|
141
162
|
|
|
142
163
|
Not intended for application code:
|
|
143
164
|
|
|
144
|
-
- `
|
|
145
|
-
|
|
146
|
-
- `stimulus_dsl_builder` — the builder accessor; `protected`, used only by inheritance
|
|
147
|
-
merging.
|
|
165
|
+
- `declarations` — frozen `Vident::Internals::Declarations` aggregate (own + inherited);
|
|
166
|
+
`protected`, consumed by the Resolver at render time.
|
|
148
167
|
|
|
149
168
|
---
|
|
150
169
|
|
|
151
170
|
## 3. `stimulus do ... end` block
|
|
152
171
|
|
|
153
|
-
Evaluated by `Vident::
|
|
172
|
+
Evaluated by `Vident::Internals::DSL` (`lib/vident/internals/dsl.rb`). Multiple
|
|
154
173
|
`stimulus do` blocks on the same class accumulate. A subclass's blocks are merged with
|
|
155
174
|
every parent's blocks on first access (subclass entries appended to positional kinds;
|
|
156
175
|
subclass wins on conflicts for keyed kinds).
|
|
157
176
|
|
|
158
|
-
Every DSL method returns `self`
|
|
159
|
-
|
|
160
|
-
|
|
177
|
+
Every DSL method returns `self` (for the singular primitives `action`/`target`, the
|
|
178
|
+
fluent **builder** is returned instead — chain methods also return self). All DSL
|
|
179
|
+
entries may use a `Proc` anywhere a value is expected; procs are evaluated via
|
|
180
|
+
`instance_exec` on the component instance at render time (or at `after_initialize`
|
|
181
|
+
for purely static entries).
|
|
161
182
|
|
|
162
183
|
### Methods on the builder
|
|
163
184
|
|
|
164
|
-
|
|
185
|
+
**Controllers.** Primary form is the singular `controller`; plural `controllers`
|
|
186
|
+
accumulates paths without the `as:` alias.
|
|
187
|
+
|
|
188
|
+
- `controller(path, as: alias_sym = nil)` — declare a cross-controller path on
|
|
189
|
+
the root element. Optional `as:` registers an alias looked up by
|
|
190
|
+
`action(...).on_controller(alias_sym)` / `on_controller: alias_sym`. Paths
|
|
191
|
+
may be `String` (`"admin/users"`) or `Symbol` (`:admin_users`).
|
|
192
|
+
- `controllers(*paths)` — one entry per path. Array entries splat into the
|
|
193
|
+
singular parser (so `[path, as: sym]` tuples work when building
|
|
194
|
+
programmatically).
|
|
195
|
+
- `no_stimulus_controller` — class-level, **not** inside the block. Suppresses
|
|
196
|
+
the implied controller. Raises `Vident::DeclarationError` if any DSL entries
|
|
197
|
+
were subsequently added.
|
|
198
|
+
|
|
199
|
+
**Actions.** Primary form is the singular `action(*args, **meta)` which returns
|
|
200
|
+
an `Internals::ActionBuilder`. Chain methods pre-applied via kwargs are equivalent
|
|
201
|
+
to calling the setters explicitly.
|
|
202
|
+
|
|
203
|
+
- `action(*args, **meta) -> ActionBuilder` — builder state:
|
|
204
|
+
- Positional `*args` shapes (`base_descriptor` pattern-matches):
|
|
205
|
+
- `(Symbol)` → method on implied (no event)
|
|
206
|
+
- `(Symbol, Symbol)` → `(event, method)` on implied
|
|
207
|
+
- `(Symbol, String, Symbol)` → `(event, controller_path, method)`
|
|
208
|
+
- `(Hash)` → full descriptor (`:method`, `:event`, `:controller`, `:options`, `:keyboard`, `:window`)
|
|
209
|
+
- Kwargs `**meta` (equivalent to the fluent chain methods):
|
|
210
|
+
- `on:` (Symbol/String) → event
|
|
211
|
+
- `call_method:` (Symbol/String) → override the method name
|
|
212
|
+
- `modifier:` (Symbol or Array) → Stimulus options whitelist (see §4.2)
|
|
213
|
+
- `keyboard:` (String) → `keydown.<key>` filter suffix
|
|
214
|
+
- `window:` (Boolean) → `@window` suffix
|
|
215
|
+
- `on_controller:` (Symbol) → resolve against a `controller ..., as: sym` alias
|
|
216
|
+
- `when:` (Proc / callable) → render-time predicate; `false`/`nil` drops the entry
|
|
217
|
+
- Unknown kwargs raise `ArgumentError`.
|
|
218
|
+
- Chain methods on the returned builder: `.on(event)`, `.call_method(name)`,
|
|
219
|
+
`.modifier(*opts)`, `.keyboard(str)`, `.window`, `.on_controller(sym)`,
|
|
220
|
+
`.when(callable = nil, &block)`. Each returns the builder.
|
|
221
|
+
- `actions(*entries)` — legacy plural form, still accepted. Each entry is one of:
|
|
165
222
|
- `Symbol` → `implied#<jsSymbol>`
|
|
166
223
|
- `[Symbol, Symbol]` → `<event>-><implied>#<jsMethod>`
|
|
167
224
|
- `[Symbol, String, Symbol]` → `<event>-><stimulized-path>#<jsMethod>`
|
|
168
|
-
- `String` containing `#` → parsed literally (pass-through)
|
|
169
|
-
|
|
170
|
-
- `
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
225
|
+
- `String` containing `#` → parsed literally (pass-through).
|
|
226
|
+
- `Hash` → descriptor keys as above.
|
|
227
|
+
- `Proc` → evaluated at render time; `nil`/`false` drops.
|
|
228
|
+
|
|
229
|
+
**Alias resolution.** When an action descriptor's `:controller` is a `Symbol`, the
|
|
230
|
+
resolver looks it up in the class's declared alias map (`controller X, as: sym`
|
|
231
|
+
entries) and substitutes the full path before parsing. Unknown alias →
|
|
232
|
+
`Vident::DeclarationError`. Alias resolution also runs on runtime inputs
|
|
233
|
+
(`stimulus_actions:` prop, `root_element_attributes[:stimulus_actions]`) that
|
|
234
|
+
carry a Hash with a `Symbol` `:controller`.
|
|
235
|
+
|
|
236
|
+
**Targets.** Singular `target` returns a `TargetBuilder` whose only chain method
|
|
237
|
+
is `.when`; plural `targets` accepts the same positional shapes as before.
|
|
238
|
+
|
|
239
|
+
- `target(*args) -> TargetBuilder` — chain `.when(callable = nil, &block)` for
|
|
240
|
+
conditional inclusion; without a chain, the builder passes `*args` through.
|
|
241
|
+
- `targets(*entries)` — each entry is one of:
|
|
176
242
|
- `Symbol` → target on the implied controller
|
|
177
243
|
- `String` → pass-through target name
|
|
178
244
|
- `[String, Symbol]` → target on the named cross-controller
|
|
179
|
-
- `Proc` —
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
`
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
- `
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
245
|
+
- `Proc` — `nil` return drops the entry.
|
|
246
|
+
|
|
247
|
+
**Keyed primitives.** `values`, `params`, `classes`, `outlets` keep the plural
|
|
248
|
+
kwargs form and add singular `value`/`param`/`class_map`/`outlet` that take
|
|
249
|
+
`(name, *args, **meta)`:
|
|
250
|
+
|
|
251
|
+
- `values(**kvs)` / `value(name, *args, **meta)` — keyed. Values may be
|
|
252
|
+
`String`/`Number`/`Boolean` (stringified), `Array`/`Hash` (JSON-serialised),
|
|
253
|
+
`Vident::StimulusNull` (emits literal `"null"`), or a `Proc` resolving to
|
|
254
|
+
any of the above. A resolved `nil` omits the attribute. Singular supports
|
|
255
|
+
`value :count, static: 0` and `value :clicked_count, from_prop: true` meta
|
|
256
|
+
forms.
|
|
257
|
+
- `params(**kvs)` / `param(name, *args, **meta)` — same serialisation rules.
|
|
258
|
+
- `classes(**kvs)` / `class_map(name, *args, **meta)` — value is `String` or
|
|
259
|
+
`Array(String)`; array joined with single space.
|
|
260
|
+
- `outlets(positional_hash = nil, **kvs)` / `outlet(name, *args, **meta)` —
|
|
261
|
+
value is a `String` CSS selector, a `Proc` returning one, or a pre-built
|
|
262
|
+
outlet value object. `outlets({"admin--users" => ".sel"})` accepts a
|
|
263
|
+
positional Hash so identifiers containing `--` (not valid Ruby kwarg keys)
|
|
264
|
+
work.
|
|
265
|
+
- `values_from_props(*prop_names)` — keyed, sidecar to `values`. Mirrors each
|
|
266
|
+
prop's current `@ivar` value at render time. Prop names are Symbols.
|
|
196
267
|
|
|
197
268
|
### What the builder emits
|
|
198
269
|
|
|
199
|
-
`
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
270
|
+
`to_declarations` (called on the `Vident::Internals::DSL` instance when the block
|
|
271
|
+
closes) returns a frozen `Vident::Internals::Declarations` struct. The struct is a
|
|
272
|
+
`Data.define(...)` value object with these fields — all frozen arrays:
|
|
273
|
+
|
|
274
|
+
| Field | Content |
|
|
275
|
+
| ------------------ | -------------------------------------------------------------------------- |
|
|
276
|
+
| `controllers` | `Array` of `Declaration` entries (each wraps a path + optional `as:` alias). |
|
|
277
|
+
| `actions` | `Array` of `Declaration` entries, one per `action(...)` call. |
|
|
278
|
+
| `targets` | `Array` of `Declaration` entries, one per `target(...)` call. |
|
|
279
|
+
| `outlets` | `Array` of `[key, Declaration]` pairs (keyed; last-write-wins on same key).|
|
|
280
|
+
| `values` | `Array` of `[key, Declaration]` pairs. |
|
|
281
|
+
| `params` | `Array` of `[key, Declaration]` pairs. |
|
|
282
|
+
| `class_maps` | `Array` of `[key, Declaration]` pairs. |
|
|
283
|
+
| `values_from_props`| `Array(Symbol)` — prop names listed via `values_from_props`. |
|
|
284
|
+
|
|
285
|
+
The struct supports `merge(other)` (subclass block merged over superclass) and
|
|
286
|
+
`any?`. Entries remain as raw `Declaration` tuples — parsing into
|
|
287
|
+
`Vident::Stimulus::*` value objects is deferred to the Resolver at render time.
|
|
288
|
+
Application code does not call `to_declarations` directly.
|
|
203
289
|
|
|
204
290
|
---
|
|
205
291
|
|
|
206
|
-
## 4. Instance-level Stimulus helpers (`Vident::
|
|
292
|
+
## 4. Instance-level Stimulus helpers (`Vident::Capabilities::StimulusParsing`)
|
|
207
293
|
|
|
208
|
-
Included into every component via `
|
|
209
|
-
`lib/vident/
|
|
294
|
+
Included into every component via `Vident::Component`. File:
|
|
295
|
+
`lib/vident/capabilities/stimulus_parsing.rb`.
|
|
210
296
|
|
|
211
297
|
### 4.1 Plural parsers `stimulus_<plural>(*args)`
|
|
212
298
|
|
|
213
299
|
Seven methods: `stimulus_controllers`, `stimulus_actions`, `stimulus_targets`,
|
|
214
300
|
`stimulus_outlets`, `stimulus_values`, `stimulus_params`, `stimulus_classes`.
|
|
215
301
|
|
|
216
|
-
Each returns a collection object (`
|
|
302
|
+
Each returns a collection object (`Vident::Stimulus::Collection`, etc.) whose `#to_h`
|
|
217
303
|
serialises to a `Hash` of `data-*` keys → values. Arg handling per input:
|
|
218
304
|
|
|
219
305
|
- no args or all-blank → empty collection
|
|
@@ -227,12 +313,12 @@ serialises to a `Hash` of `data-*` keys → values. Arg handling per input:
|
|
|
227
313
|
|
|
228
314
|
### 4.2 Singular builders `stimulus_<singular>(*args)`
|
|
229
315
|
|
|
230
|
-
Each singular builder
|
|
231
|
-
|
|
316
|
+
Each singular builder delegates to the corresponding value class's `.parse(*args, implied:, component_id:)`
|
|
317
|
+
class method. Raises `ArgumentError` (or `Vident::ParseError`) on unsupported shape or arity.
|
|
232
318
|
|
|
233
319
|
- `stimulus_controller(*)` — 0 or 1 arg. 0 args returns the implied controller; 1 arg
|
|
234
320
|
is a controller path `String`/`Symbol`.
|
|
235
|
-
- `stimulus_action(*)` — 1/2/3 args. See `
|
|
321
|
+
- `stimulus_action(*)` — 1/2/3 args. See `Vident::Stimulus::Action.parse` for all
|
|
236
322
|
accepted forms. `options:` whitelist (raises otherwise):
|
|
237
323
|
`[:once, :prevent, :stop, :passive, :"!passive", :capture, :self]`.
|
|
238
324
|
- `stimulus_target(*)` — 1 or 2 args. `(Symbol)` / `(String)` → implied controller;
|
|
@@ -258,26 +344,27 @@ Seven methods, one per primitive. Merge new attributes into the per-kind collect
|
|
|
258
344
|
ivar (e.g. `@stimulus_actions_collection`). Typical use: inside
|
|
259
345
|
`after_component_initialize`, compute runtime attributes and add them.
|
|
260
346
|
|
|
261
|
-
**
|
|
262
|
-
one action descriptor (event + method)
|
|
263
|
-
|
|
264
|
-
Array
|
|
265
|
-
|
|
347
|
+
**Array input is one entry.** `add_stimulus_actions([:click, :handle])` treats the
|
|
348
|
+
Array as *one* action descriptor (event + method pair), matching the DSL's
|
|
349
|
+
`actions [:click, :handle]` semantics. The V1 splat asymmetry — where the mutator
|
|
350
|
+
treated the Array as two separate symbol actions — was fixed in V2. To pass a
|
|
351
|
+
pre-built action object, construct it first:
|
|
352
|
+
`add_stimulus_actions(stimulus_action(:click, :handle))`.
|
|
266
353
|
|
|
267
|
-
### 4.4 Value serialisation
|
|
354
|
+
### 4.4 Value serialisation
|
|
268
355
|
|
|
269
356
|
`Array` and `Hash` → JSON. Everything else → `to_s`. `Vident::StimulusNull.to_s`
|
|
270
357
|
returns the literal string `"null"`. A `nil` reaches the DSL/prop layer and
|
|
271
|
-
is dropped by
|
|
272
|
-
|
|
358
|
+
is dropped by the Resolver before serialisation, so the data attribute is omitted
|
|
359
|
+
(not emitted as empty).
|
|
273
360
|
|
|
274
361
|
### 4.5 Name-shaping helpers
|
|
275
362
|
|
|
276
|
-
|
|
277
|
-
each path segment is `dasherize`d and segments joined with `--`.
|
|
278
|
-
- `StimulusAttributeBase.js_name(name)` — `camelize(:lower)`; `:my_thing` → `"myThing"`.
|
|
363
|
+
`Vident::Stimulus::Naming` is a `module_function` module — call its methods directly:
|
|
279
364
|
|
|
280
|
-
|
|
365
|
+
- `Vident::Stimulus::Naming.stimulize_path(path)` — `"admin/users"` → `"admin--users"`;
|
|
366
|
+
each path segment is `dasherize`d and segments joined with `--`.
|
|
367
|
+
- `Vident::Stimulus::Naming.js_name(name)` — `camelize(:lower)`; `:my_thing` → `"myThing"`.
|
|
281
368
|
|
|
282
369
|
### 4.6 Scoped events
|
|
283
370
|
|
|
@@ -287,6 +374,48 @@ Both also available as private instance methods on any `StimulusAttributeBase` s
|
|
|
287
374
|
- Class method `stimulus_scoped_event_on_window(event)` — same with `@window` suffix.
|
|
288
375
|
- Both also exist as instance methods that delegate to the class method.
|
|
289
376
|
|
|
377
|
+
### 4.7 Class-level builders
|
|
378
|
+
|
|
379
|
+
Class methods parallel to the instance singulars, useful when you need a
|
|
380
|
+
Stimulus value object without a component instance (Turbo-Stream partials,
|
|
381
|
+
JSON responses, system-test selectors).
|
|
382
|
+
|
|
383
|
+
- `MyComponent.stimulus_controller` — no args; returns the implied `Vident::Stimulus::Controller`.
|
|
384
|
+
- `MyComponent.stimulus_target(Symbol|String)` — returns `Vident::Stimulus::Target`.
|
|
385
|
+
- `MyComponent.stimulus_action(*args)` — same grammar as the instance singular, but cross-controller forms (`[String, Symbol]`, `[Symbol, String, Symbol]`) raise `Vident::ParseError`.
|
|
386
|
+
- `MyComponent.stimulus_value(name, value)` — two-arg form only; the three-arg cross-controller form raises.
|
|
387
|
+
- `MyComponent.stimulus_param(name, value)` — same constraint.
|
|
388
|
+
- `MyComponent.stimulus_class(name, css)` — same constraint.
|
|
389
|
+
- `MyComponent.stimulus_outlet(name, selector)` — **selector required**; single-arg auto-selector form raises `Vident::ParseError` (no `component_id` at class level). For cross-controller outlets, call `Vident::Stimulus::Outlet.parse(...)` directly.
|
|
390
|
+
|
|
391
|
+
Class-level output matches instance-level where both apply:
|
|
392
|
+
|
|
393
|
+
```ruby
|
|
394
|
+
ButtonComponent.stimulus_target(:submit).to_h ==
|
|
395
|
+
ButtonComponent.new.stimulus_target(:submit).to_h # => true
|
|
396
|
+
```
|
|
397
|
+
|
|
398
|
+
The implied controller is memoised per-class on the singleton; subclasses inherit the identifier path but get their own memo.
|
|
399
|
+
|
|
400
|
+
### 4.8 Root-element composition helpers
|
|
401
|
+
|
|
402
|
+
Two instance methods that return what `root_element(...)` would emit — for components that render their root tag via a third-party helper (e.g. `InlineSvg::inline_svg_tag`).
|
|
403
|
+
|
|
404
|
+
- `root_element_class_list(extra_classes = nil)` — returns a `String`. Applies the full 6-tier class cascade (`component_name`, `root_element_classes`, `root_element_attributes[:classes]`, `html_options[:class]`, `@classes` prop, then `extra_classes`) plus Tailwind-merging.
|
|
405
|
+
- `root_element_data_attributes` — returns a `Hash` with Symbol keys. Seals the Draft into a Plan (idempotent) and runs the AttributeWriter, yielding the same `data-controller` / `data-action` / `data-*-target` / etc. hash that `root_element(...)` would emit.
|
|
406
|
+
|
|
407
|
+
```ruby
|
|
408
|
+
def svg_attributes
|
|
409
|
+
{
|
|
410
|
+
id: @id,
|
|
411
|
+
class: root_element_class_list,
|
|
412
|
+
data: root_element_data_attributes
|
|
413
|
+
}
|
|
414
|
+
end
|
|
415
|
+
```
|
|
416
|
+
|
|
417
|
+
Both honour `no_stimulus_controller` (no `data-controller` in the hash; component-identifier CSS class still emitted, matching `root_element`).
|
|
418
|
+
|
|
290
419
|
---
|
|
291
420
|
|
|
292
421
|
## 5. `root_element_attributes` accepted keys
|
|
@@ -343,44 +472,44 @@ def child_element(tag_name,
|
|
|
343
472
|
|
|
344
473
|
---
|
|
345
474
|
|
|
346
|
-
## 7. `Vident::
|
|
475
|
+
## 7. `Vident::Internals::DSL` primitives
|
|
347
476
|
|
|
348
477
|
For use in advanced cases (passing typed descriptors across components, building
|
|
349
|
-
reusable shared helpers).
|
|
478
|
+
reusable shared helpers). Value classes live under `lib/vident/stimulus/`.
|
|
350
479
|
|
|
351
|
-
###
|
|
480
|
+
### Hash descriptor form
|
|
352
481
|
|
|
353
|
-
|
|
354
|
-
`
|
|
482
|
+
There is no separate `Descriptor` class in V2. The Hash form accepted by `actions`
|
|
483
|
+
(and `stimulus_actions:`) is parsed directly into `Vident::Stimulus::Action`. Accepted keys:
|
|
355
484
|
|
|
356
|
-
|
|
|
485
|
+
| Key | Type | Default |
|
|
357
486
|
| ------------- | ------------------------------------- | ------- |
|
|
358
|
-
| `method
|
|
359
|
-
| `event
|
|
360
|
-
| `controller
|
|
361
|
-
| `options
|
|
362
|
-
| `keyboard
|
|
363
|
-
| `window
|
|
487
|
+
| `method:` | `Symbol \| String` | required |
|
|
488
|
+
| `event:` | `Symbol \| String \| nil` | `nil` |
|
|
489
|
+
| `controller:` | `String \| nil` | `nil` |
|
|
490
|
+
| `options:` | `Array(Symbol)` — see §4.2 whitelist | `[]` |
|
|
491
|
+
| `keyboard:` | `String \| nil` | `nil` |
|
|
492
|
+
| `window:` | `Boolean` | `false` |
|
|
364
493
|
|
|
365
494
|
### `Vident::StimulusNull`
|
|
366
495
|
|
|
367
496
|
Frozen singleton object. `inspect` → `"Vident::StimulusNull"`; `to_s` → `"null"`.
|
|
368
497
|
See SKILL.md §1.4 for the usage contract.
|
|
369
498
|
|
|
370
|
-
### Collection
|
|
499
|
+
### Collection class
|
|
371
500
|
|
|
372
|
-
|
|
501
|
+
All primitive kinds share one parametric class: `Vident::Stimulus::Collection`,
|
|
502
|
+
parametrised on a `Kind` record from `Vident::Internals::Registry`.
|
|
373
503
|
|
|
374
|
-
-
|
|
375
|
-
`
|
|
376
|
-
-
|
|
377
|
-
- `
|
|
378
|
-
joined by space.
|
|
379
|
-
- `
|
|
380
|
-
|
|
381
|
-
- `
|
|
382
|
-
|
|
383
|
-
- `StimulusOutletCollection` → same.
|
|
504
|
+
- Methods: `each`, `to_a`, `size`, `length`, `empty?`, `any?`, `to_h`, `to_hash`,
|
|
505
|
+
`merge(other)` (single same-kind Collection; raises `ArgumentError` on mismatch).
|
|
506
|
+
- `#to_h` shape per kind:
|
|
507
|
+
- `actions` → `{action: "…"}` with entries joined by space.
|
|
508
|
+
- `controllers` → `{controller: "…"}` with non-empty entries joined by space.
|
|
509
|
+
- `targets` → one key per controller-target attribute; multiple targets on
|
|
510
|
+
the same controller joined with a single space.
|
|
511
|
+
- `values`, `params`, `class_maps` → merged per-data-attribute Hash.
|
|
512
|
+
- `outlets` → same.
|
|
384
513
|
|
|
385
514
|
---
|
|
386
515
|
|
|
@@ -398,7 +527,7 @@ File: `lib/vident/caching.rb`.
|
|
|
398
527
|
into this class's `component_modified_time`, so sub-component edits bust the
|
|
399
528
|
parent's cache.
|
|
400
529
|
- `component_modified_time` — memoised in `Rails.env.production?`, otherwise recomputed
|
|
401
|
-
on every call. Raises `
|
|
530
|
+
on every call. Raises `Vident::ConfigurationError` if the host class has no
|
|
402
531
|
`cache_component_modified_time` (base classes provide it).
|
|
403
532
|
|
|
404
533
|
### Instance methods
|
|
@@ -407,13 +536,22 @@ File: `lib/vident/caching.rb`.
|
|
|
407
536
|
- `cacheable?` — `respond_to?(:cache_key)`.
|
|
408
537
|
- `cache_key` — defined when `with_cache_key` has been called; returns
|
|
409
538
|
`"#{class.name}/#{cache_keys_for_sources(...).join("/")}"`, optionally suffixed with
|
|
410
|
-
`ENV["RAILS_CACHE_ID"]`. Raises `
|
|
539
|
+
`ENV["RAILS_CACHE_ID"]`. Raises `Vident::ConfigurationError` if the computed key is blank.
|
|
411
540
|
- `cache_key_modifier` — returns `ENV["RAILS_CACHE_ID"]` (may be nil).
|
|
412
541
|
|
|
413
542
|
`with_cache_key` without any attrs is valid — the call still appends
|
|
414
543
|
`:component_modified_time` and `:to_h`, so the cache key reflects the template mtime
|
|
415
544
|
plus the component's full prop hash.
|
|
416
545
|
|
|
546
|
+
### Fragment-caching the render: `cache_component`
|
|
547
|
+
|
|
548
|
+
Available on both adapter base classes (`Vident::Phlex::HTML` and `Vident::ViewComponent::Base`). Wraps a block of render output with Rails.cache using the Vident-computed `cache_key`:
|
|
549
|
+
|
|
550
|
+
- `cache_component(*extra_keys, **options, &block)` — on Phlex, delegates to `Phlex::SGML#cache([cache_key, *extra_keys], **options, &block)`. On ViewComponent, uses `Rails.cache.fetch([cache_key, *extra_keys], **options) { capture(&block) }`.
|
|
551
|
+
- Raises `Vident::ConfigurationError` if the component is not cacheable (no `with_cache_key` declared).
|
|
552
|
+
- `extra_keys` let the caller add per-render state to the cache key without modifying `with_cache_key`.
|
|
553
|
+
- Phlex usage: inside `view_template`. ViewComponent usage: inside a `def call` method; sidecar ERB templates can use Rails' native `<% cache cache_key do %> ... <% end %>` instead.
|
|
554
|
+
|
|
417
555
|
---
|
|
418
556
|
|
|
419
557
|
## 9. `Vident::StableId`
|
|
@@ -467,15 +605,15 @@ Included into every component. File: `lib/vident/tailwind.rb`.
|
|
|
467
605
|
the `tailwind_merge` gem is loaded; otherwise returns `nil`.
|
|
468
606
|
- `tailwind_merge_available?` — `true` iff `::TailwindMerge::Merger` is defined.
|
|
469
607
|
|
|
470
|
-
`Vident::ClassListBuilder` invokes `tailwind_merger.merge(class_string)` automatically
|
|
471
|
-
at the final stage of its `
|
|
608
|
+
`Vident::Internals::ClassListBuilder` invokes `tailwind_merger.merge(class_string)` automatically
|
|
609
|
+
at the final stage of its `call(...)` when a merger is provided. No per-component
|
|
472
610
|
opt-in is required beyond adding the gem to the Gemfile.
|
|
473
611
|
|
|
474
612
|
---
|
|
475
613
|
|
|
476
614
|
## 11. `class_list_for_stimulus_classes`
|
|
477
615
|
|
|
478
|
-
Instance method on every component. File: `lib/vident/
|
|
616
|
+
Instance method on every component. File: `lib/vident/capabilities/class_list_building.rb`.
|
|
479
617
|
|
|
480
618
|
```ruby
|
|
481
619
|
class_list_for_stimulus_classes(*names) -> String
|
|
@@ -493,26 +631,32 @@ Names may be `Symbol` or `String`; both are normalised via `dasherize`.
|
|
|
493
631
|
## 12. Rails engine hooks
|
|
494
632
|
|
|
495
633
|
- `Vident::Engine` (`lib/vident/engine.rb`) — autoloaded when Rails is defined.
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
634
|
+
Registers Zeitwerk inflections for Vident's non-standard file names (`"dsl"` →
|
|
635
|
+
`"DSL"`, `"html"` → `"HTML"`) so `Vident::Internals::DSL` and
|
|
636
|
+
`Vident::Phlex::HTML` resolve correctly. It does not load any generators at
|
|
637
|
+
engine init — `Vident::Generators::InstallGenerator` is autoloaded on demand
|
|
638
|
+
when `bin/rails generate vident:install` is invoked.
|
|
499
639
|
|
|
500
640
|
---
|
|
501
641
|
|
|
502
642
|
## 13. What's not in the public API
|
|
503
643
|
|
|
504
|
-
The following show up in `lib/vident
|
|
644
|
+
The following show up in `lib/vident/` but are explicitly internal:
|
|
505
645
|
|
|
506
|
-
- `Vident::
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
646
|
+
- `Vident::Internals::Registry::KINDS` / `Vident::Internals::Registry::Kind` — the
|
|
647
|
+
registry that drives every plural parser, mutator, and DSL primitive. Don't rely on
|
|
648
|
+
these in application code.
|
|
649
|
+
- `Vident::Stimulus::Naming` — pure naming helpers (`stimulize_path`, `js_name`)
|
|
650
|
+
consumed by value classes. The two `module_function` methods documented in §4.5
|
|
651
|
+
are callable directly (`Vident::Stimulus::Naming.stimulize_path(...)`) but the
|
|
652
|
+
module itself is not designed for subclassing or further extension.
|
|
653
|
+
- `Vident::Internals::AttributeWriter` — used internally by `root_element_attributes`
|
|
511
654
|
resolution and `child_element`. Takes a collection-per-primitive kwarg hash and
|
|
512
655
|
merges their `to_h` outputs.
|
|
513
|
-
- `Vident::ClassListBuilder` — invoked internally by
|
|
514
|
-
|
|
515
|
-
|
|
656
|
+
- `Vident::Internals::ClassListBuilder` — invoked internally by
|
|
657
|
+
`Vident::Capabilities::ClassListBuilding#class_list_for_stimulus_classes`.
|
|
658
|
+
- `Vident::Capabilities::ChildElementRendering`, `Vident::Capabilities::RootElementRendering`,
|
|
659
|
+
`Vident::Capabilities::StimulusMutation`, `Vident::Capabilities::StimulusDraft` —
|
|
516
660
|
included into components; their private/internal methods are not API.
|
|
517
|
-
- `Vident::
|
|
518
|
-
|
|
661
|
+
- `Vident::Stimulus::Naming.stimulize_path(path)` — the canonical path → identifier
|
|
662
|
+
helper. (V1's `stimulus_identifier_from_path` on `Vident::Component` was removed in V2.)
|
data/skills/vident/examples.md
CHANGED
|
@@ -176,7 +176,7 @@ export default class extends Controller {
|
|
|
176
176
|
}
|
|
177
177
|
```
|
|
178
178
|
|
|
179
|
-
### Detail panel (StimulusNull + keyboard modifier action)
|
|
179
|
+
### Detail panel (StimulusNull + keyboard modifier action + alias resolution)
|
|
180
180
|
|
|
181
181
|
```ruby
|
|
182
182
|
module Dashboard
|
|
@@ -192,14 +192,27 @@ module Dashboard
|
|
|
192
192
|
|
|
193
193
|
classes state: "fixed right-0 top-0 h-full w-80 border-l bg-white p-6 shadow-xl transition-transform duration-200 translate-x-full"
|
|
194
194
|
|
|
195
|
-
#
|
|
196
|
-
#
|
|
197
|
-
#
|
|
198
|
-
#
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
195
|
+
# Secondary controller stacked on the same root, given a short alias so
|
|
196
|
+
# later action entries can refer to it by `:dismissable` instead of the
|
|
197
|
+
# full path. Emits `data-controller="dashboard--detail-panel-component
|
|
198
|
+
# dashboard--dismissable"`.
|
|
199
|
+
controller "dashboard_v2/dismissable", as: :dismissable
|
|
200
|
+
|
|
201
|
+
# 1. Proc + scoped window event — opens the panel when a card emits `selected`.
|
|
202
|
+
actions -> { [ReleaseCardComponent.stimulus_scoped_event_on_window(:selected), :handle_selected] }
|
|
203
|
+
|
|
204
|
+
# 2. Kwargs shorthand for the keyboard filter. Equivalent to:
|
|
205
|
+
# `action(:close).on(:keydown).keyboard("esc").window`.
|
|
206
|
+
# Emits `keydown.esc@window->dashboard--detail-panel-component#close`.
|
|
207
|
+
action :close, on: :keydown, keyboard: "esc", window: true
|
|
208
|
+
|
|
209
|
+
# 3. Fluent chain routed through the `:dismissable` alias. Emits
|
|
210
|
+
# `keydown.backspace@window->dashboard--dismissable#close` instead of
|
|
211
|
+
# the implied controller — alias resolved by Internals::Resolver.
|
|
212
|
+
action(:close).on(:keydown).keyboard("backspace").window.on_controller(:dismissable)
|
|
213
|
+
|
|
214
|
+
# 4. Plain `:close` — wired to the close button's local click target.
|
|
215
|
+
action :close
|
|
203
216
|
end
|
|
204
217
|
|
|
205
218
|
def view_template
|
|
@@ -308,7 +321,7 @@ parent's action:
|
|
|
308
321
|
<% end %>
|
|
309
322
|
```
|
|
310
323
|
|
|
311
|
-
`greeter.stimulus_action(:click, :greet)` returns a `Vident::
|
|
324
|
+
`greeter.stimulus_action(:click, :greet)` returns a `Vident::Stimulus::Action` whose
|
|
312
325
|
`controller` is the parent's (greeter's) identifier, so the click handler on the child's
|
|
313
326
|
button routes to `greeter-with-trigger-component#greet`, not to the child.
|
|
314
327
|
|