phlex-reactive 0.16.2 → 0.16.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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +22 -0
- data/README.md +33 -4
- data/app/javascript/phlex/reactive/features/bindings.js +37 -7
- data/app/javascript/phlex/reactive/features/bindings.min.js +2 -2
- data/app/javascript/phlex/reactive/features/bindings.min.js.map +3 -3
- data/app/javascript/phlex/reactive/inspect.js +4 -1
- data/app/javascript/phlex/reactive/inspect.min.js +2 -2
- data/app/javascript/phlex/reactive/inspect.min.js.map +3 -3
- data/app/javascript/phlex/reactive/reactive_controller.min.js +4 -4
- data/app/javascript/phlex/reactive/reactive_controller.min.js.map +3 -3
- data/lib/phlex/reactive/component/helpers.rb +32 -1
- data/lib/phlex/reactive/component/identity.rb +1 -1
- data/lib/phlex/reactive/version.rb +1 -1
- metadata +1 -1
|
@@ -741,7 +741,18 @@ module Phlex
|
|
|
741
741
|
# exactly one of field/input: per call — the field form stays the
|
|
742
742
|
# blessed default:
|
|
743
743
|
# reactive_filter(input: "#user_tags_query")
|
|
744
|
-
|
|
744
|
+
#
|
|
745
|
+
# Issue #425: `match:` picks where the query must sit in the haystack —
|
|
746
|
+
# :substring (anywhere, the default), :prefix (at its start) or
|
|
747
|
+
# :word_start (at its start, or right after whitespace or one of
|
|
748
|
+
# - ' ( ) , . /). A long alphabetical list (countries, cities, people)
|
|
749
|
+
# wants :word_start, so "n" keeps Nantes and New York, not every name
|
|
750
|
+
# with an n in it. `fold: true` folds diacritics on BOTH sides before
|
|
751
|
+
# comparing, so "zur" finds Zürich and "zür" still does. The defaults
|
|
752
|
+
# emit nothing, so an existing filter's wire is byte-identical:
|
|
753
|
+
# reactive_filter(:q, match: :word_start, fold: true)
|
|
754
|
+
def reactive_filter(field = nil, input: nil, option: nil, group: nil, empty: nil,
|
|
755
|
+
match: :substring, fold: false)
|
|
745
756
|
# nil-presence, NOT truthiness: `input: cond && "#sel"` with cond false
|
|
746
757
|
# must fail loudly in filter_selector! below (a boolean is never a
|
|
747
758
|
# selector), never slip into the field branch and emit a dead binding.
|
|
@@ -768,6 +779,10 @@ module Phlex
|
|
|
768
779
|
# byte-stable wire and always-emit an attribute the client would then query).
|
|
769
780
|
data[:reactive_filter_group] = filter_selector!(:group, group) if group
|
|
770
781
|
data[:reactive_filter_empty] = filter_selector!(:empty, empty) if empty
|
|
782
|
+
# match:/fold: too (issue #425): the defaults emit nothing.
|
|
783
|
+
mode = filter_match!(match)
|
|
784
|
+
data[:reactive_filter_match] = mode.to_s unless mode == :substring
|
|
785
|
+
data[:reactive_filter_fold] = "true" if fold
|
|
771
786
|
|
|
772
787
|
{ data: }
|
|
773
788
|
end
|
|
@@ -1427,8 +1442,24 @@ module Phlex
|
|
|
1427
1442
|
LEGACY_SHOW_PREDICATE_KEYS = %i[equals not in gte gt lte lt].freeze
|
|
1428
1443
|
LEGACY_SHOW_CONNECTIVE_KEYS = %i[all any].freeze
|
|
1429
1444
|
|
|
1445
|
+
# reactive_filter's match: modes (issue #425), in the order the error names them.
|
|
1446
|
+
FILTER_MATCH_MODES = %i[substring prefix word_start].freeze
|
|
1447
|
+
private_constant :FILTER_MATCH_MODES
|
|
1448
|
+
|
|
1430
1449
|
private
|
|
1431
1450
|
|
|
1451
|
+
# reactive_filter's match: (issue #425), a Symbol or a String naming one
|
|
1452
|
+
# of FILTER_MATCH_MODES (the reactive_persist storage: precedent).
|
|
1453
|
+
# Anything else raises at render: the client would fall back to
|
|
1454
|
+
# substring matching and the list would narrow the wrong way.
|
|
1455
|
+
def filter_match!(match)
|
|
1456
|
+
mode = match.to_sym if match.is_a?(Symbol) || match.is_a?(String)
|
|
1457
|
+
return mode if FILTER_MATCH_MODES.include?(mode)
|
|
1458
|
+
|
|
1459
|
+
raise ArgumentError,
|
|
1460
|
+
"reactive_filter match: must be one of #{FILTER_MATCH_MODES.join(", ")}, got #{match.inspect}"
|
|
1461
|
+
end
|
|
1462
|
+
|
|
1432
1463
|
# A reactive_filter/reactive_listnav selector, validated non-blank and
|
|
1433
1464
|
# stringified (issue #163). A blank selector is a dead binding — the
|
|
1434
1465
|
# client would silently match nothing — so it fails loudly at render,
|
|
@@ -10,7 +10,7 @@ module Phlex
|
|
|
10
10
|
#
|
|
11
11
|
# THE token hot path. Both memos below are bare defined?/||= fast paths
|
|
12
12
|
# ON PURPOSE: a render must never pay a per-read generation compare
|
|
13
|
-
# (issue #115 invariant, .
|
|
13
|
+
# (issue #115 invariant, AGENTS.md → Performance). Coherence comes
|
|
14
14
|
# from the WRITE side instead — Component::Registry.bump! sweeps these
|
|
15
15
|
# memos off the declaring class and all its descendants whenever any
|
|
16
16
|
# registry declaration lands (class-load-shaped, rare), so they can't go
|