phlex-reactive 0.9.2 → 0.9.3

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.
@@ -399,6 +399,54 @@ module Phlex
399
399
  span(**mix({ data: { reactive_text: name.to_s } }, attrs)) { initial }
400
400
  end
401
401
 
402
+ # Value-conditional visibility (issue #161) — the x-show / data-show /
403
+ # wire:show equivalent, entirely client-side. Spread onto the element to
404
+ # show/hide; it declares which OWNED field controls it plus ONE literal
405
+ # predicate, and the generic controller toggles the `hidden` attribute
406
+ # from the field's CURRENT value on every input/change — no round trip,
407
+ # no token, no bespoke Stimulus controller:
408
+ #
409
+ # div(**reactive_show(:mode, not: "off")) { "details" }
410
+ # div(**reactive_show(:kind, equals: "premium")) { "premium panel" }
411
+ # div(**reactive_show(:size, in: %w[l xl])) { "surcharge note" }
412
+ # div(**reactive_show(:gift, equals: true)) { "gift message" }
413
+ #
414
+ # Exactly one predicate — equals:, not:, or in: (a list) — and every
415
+ # value is STRINGIFIED for a literal match against the field's value
416
+ # (a checkbox compares its checked state as "true"/"false", so
417
+ # `equals: true` is the checkbox form; a radio group reads the checked
418
+ # radio's value). This is a DECLARED LITERAL MATCH, never an expression
419
+ # — there is no eval surface (default-deny, like the op vocabulary).
420
+ #
421
+ # Scope: presentational only, strictly less powerful than the js ops —
422
+ # it reads an owned field (#15 ownership) and toggles `hidden` on an
423
+ # owned element. The client seeds visibility at connect and reconciles
424
+ # after a morph; render the initial `hidden:` yourself (from the same
425
+ # server state that renders the field) to avoid a first-paint flash.
426
+ # Extra attrs deep-merge over the binding (mix), like reactive_field.
427
+ def reactive_show(field, **options)
428
+ predicates = options.slice(*SHOW_PREDICATE_KEYS)
429
+ attrs = options.except(*SHOW_PREDICATE_KEYS)
430
+ unless predicates.size == 1
431
+ raise ArgumentError,
432
+ "reactive_show(#{field.inspect}) needs exactly one predicate — equals:, not:, or " \
433
+ "in: — got #{predicates.keys.inspect}"
434
+ end
435
+
436
+ key, value = predicates.first
437
+ data = { reactive_show_field: field.to_s }
438
+ if key == :in
439
+ list = Array(value).map(&:to_s)
440
+ raise ArgumentError, "reactive_show(#{field.inspect}) in: needs at least one value" if list.empty?
441
+
442
+ data[:reactive_show_in] = list.to_json
443
+ else
444
+ data[:"reactive_show_#{key}"] = value.to_s
445
+ end
446
+
447
+ mix({ data: }, attrs)
448
+ end
449
+
402
450
  # Scoped busy indicator (issue #99). Marks an element so the generic
403
451
  # controller toggles `data-reactive-busy` on it ONLY while `action` is in
404
452
  # flight — the scoped sibling of the always-on `data-reactive-busy` the
@@ -485,6 +533,13 @@ module Phlex
485
533
  reactive_record_for_nested.update!(**nested_attributes(association, attrs), **extra)
486
534
  end
487
535
 
536
+ # The declared reactive_show predicates (issue #161): a literal match on
537
+ # the controlling field's current value. Exactly one per binding —
538
+ # enforced loudly at render (a dead binding must not no-op in the
539
+ # browser). `not`/`in` are Ruby keywords, so they arrive via **options
540
+ # rather than named kwargs.
541
+ SHOW_PREDICATE_KEYS = %i[equals not in].freeze
542
+
488
543
  # The declared optimistic-hint class ops (issue #98): the cosmetic class
489
544
  # vocabulary the client applies instantly and reverts on failure. Enforced
490
545
  # at build time in optimistic_hint_json (default-deny — a dead hint fails
@@ -2,6 +2,6 @@
2
2
 
3
3
  module Phlex
4
4
  module Reactive
5
- VERSION = "0.9.2"
5
+ VERSION = "0.9.3"
6
6
  end
7
7
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: phlex-reactive
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.9.2
4
+ version: 0.9.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Mikael Henriksson