stimulus_plumbers 0.4.13 → 0.4.15

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 (42) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +19 -0
  3. data/README.md +3 -1
  4. data/app/assets/javascripts/stimulus-plumbers/controllers.manifest.json +52 -0
  5. data/app/assets/javascripts/stimulus-plumbers/index.es.js +295 -181
  6. data/app/assets/javascripts/stimulus-plumbers/index.es.js.map +1 -1
  7. data/app/assets/javascripts/stimulus-plumbers/index.umd.js +1 -1
  8. data/app/assets/javascripts/stimulus-plumbers/index.umd.js.map +1 -1
  9. data/config/locales/en.yml +12 -0
  10. data/docs/component/combobox.md +3 -2
  11. data/docs/component/form.md +36 -4
  12. data/docs/component/plumber.md +40 -1
  13. data/docs/component/progress.md +29 -9
  14. data/lib/stimulus_plumbers/components/card/slots.rb +0 -2
  15. data/lib/stimulus_plumbers/components/combobox/{builder.rb → config.rb} +7 -11
  16. data/lib/stimulus_plumbers/components/combobox.rb +12 -12
  17. data/lib/stimulus_plumbers/components/password_strength.rb +103 -0
  18. data/lib/stimulus_plumbers/components/progress/shared.rb +31 -0
  19. data/lib/stimulus_plumbers/components/progress_bar.rb +44 -20
  20. data/lib/stimulus_plumbers/components/progress_meter.rb +16 -14
  21. data/lib/stimulus_plumbers/components/progress_ring.rb +7 -22
  22. data/lib/stimulus_plumbers/components/timeline/event/slots.rb +0 -1
  23. data/lib/stimulus_plumbers/form/builder.rb +15 -4
  24. data/lib/stimulus_plumbers/form/fields/inputs/password/revealable.rb +72 -0
  25. data/lib/stimulus_plumbers/form/fields/inputs/password/strength.rb +31 -0
  26. data/lib/stimulus_plumbers/form/fields/inputs/password.rb +34 -65
  27. data/lib/stimulus_plumbers/helpers/progress_helper.rb +10 -2
  28. data/lib/stimulus_plumbers/password/requirements.rb +182 -0
  29. data/lib/stimulus_plumbers/password_strength_validator.rb +29 -0
  30. data/lib/stimulus_plumbers/plumber/config.rb +37 -0
  31. data/lib/stimulus_plumbers/plumber/dispatcher/callable_inspector.rb +4 -0
  32. data/lib/stimulus_plumbers/plumber/slots.rb +2 -2
  33. data/lib/stimulus_plumbers/themes/icons/external.rb +1 -1
  34. data/lib/stimulus_plumbers/themes/schema/icon.rb +15 -4
  35. data/lib/stimulus_plumbers/themes/schema.rb +12 -4
  36. data/lib/stimulus_plumbers/version.rb +1 -1
  37. data/lib/stimulus_plumbers.rb +7 -1
  38. data/vendor/component/manifest.json +9 -0
  39. data/vendor/controller/docs/password-strength.md +38 -0
  40. data/vendor/controller/docs/progress.md +33 -16
  41. data/vendor/controller/manifest.json +52 -0
  42. metadata +10 -2
@@ -57,10 +57,21 @@ module StimulusPlumbers
57
57
  private
58
58
 
59
59
  def resolve_svg_attrs(svg_data)
60
- SVG_ATTR_DEFAULTS
61
- .merge(svg_data.slice(*SVG_ATTR_DEFAULTS.keys))
62
- .transform_keys { |key| SVG_ATTR_NAMES.fetch(key, key.to_s) }
63
- .transform_values(&:to_s)
60
+ SVG_ATTR_DEFAULTS.merge(svg_data).filter_map do |key, value|
61
+ next unless svg_attr_allowed?(key)
62
+
63
+ [svg_attr_name(key), value.to_s]
64
+ end.to_h
65
+ end
66
+
67
+ def svg_attr_allowed?(key)
68
+ SVG_ATTR_DEFAULTS.key?(key) || data_or_aria_attr?(key)
69
+ end
70
+
71
+ def svg_attr_name(key)
72
+ return key.to_s.tr("_", "-") if data_or_aria_attr?(key)
73
+
74
+ SVG_ATTR_NAMES.fetch(key, key.to_s)
64
75
  end
65
76
 
66
77
  def resolve_element_attrs(element_data)
@@ -159,6 +159,12 @@ module StimulusPlumbers
159
159
  error: { default: false, validate: Ranges::BOOL },
160
160
  floating: { default: nil, validate: [nil, *Form::Floating::Ranges::TYPE] }
161
161
  }.freeze,
162
+ password_strength_wrapper: {}.freeze,
163
+ password_strength_rules_heading: {}.freeze,
164
+ password_strength_rules: {}.freeze,
165
+ password_strength_rule: {}.freeze,
166
+ password_strength_rule_icon: {}.freeze,
167
+ password_strength_level: {}.freeze,
162
168
  form_field_input_select: {
163
169
  error: { default: false, validate: Ranges::BOOL },
164
170
  floating: { default: nil, validate: [nil, *Form::Floating::Ranges::TYPE] }
@@ -250,10 +256,12 @@ module StimulusPlumbers
250
256
  }.freeze
251
257
 
252
258
  PROGRESS = {
253
- progress_bar: {}.freeze,
254
- progress_bar_fill: {}.freeze,
255
- progress_ring: {}.freeze,
256
- progress_meter: {}.freeze
259
+ progress_bar: {}.freeze,
260
+ progress_bar_fill: {}.freeze,
261
+ progress_segmented: {}.freeze,
262
+ progress_segment: {}.freeze,
263
+ progress_ring: { size: { default: nil, validate: %i[sm md lg] } }.freeze,
264
+ progress_meter: {}.freeze
257
265
  }.freeze
258
266
 
259
267
  TIMELINE = {
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module StimulusPlumbers
4
- VERSION = "0.4.13"
4
+ VERSION = "0.4.15"
5
5
  end
@@ -13,8 +13,11 @@ require_relative "stimulus_plumbers/logger"
13
13
  # -- Plumber base --
14
14
  require_relative "stimulus_plumbers/plumber/dispatcher"
15
15
  require_relative "stimulus_plumbers/plumber/slots"
16
+ require_relative "stimulus_plumbers/plumber/config"
16
17
  require_relative "stimulus_plumbers/plumber/base"
17
18
 
19
+ require_relative "stimulus_plumbers/password/requirements"
20
+
18
21
  # -- UI components --
19
22
  require_relative "stimulus_plumbers/components/icon"
20
23
  require_relative "stimulus_plumbers/components/indicator"
@@ -46,9 +49,11 @@ require_relative "stimulus_plumbers/components/input_group"
46
49
  require_relative "stimulus_plumbers/components/popover"
47
50
  require_relative "stimulus_plumbers/components/popover/trigger"
48
51
  require_relative "stimulus_plumbers/components/popover/panel"
52
+ require_relative "stimulus_plumbers/components/progress/shared"
49
53
  require_relative "stimulus_plumbers/components/progress_bar"
50
54
  require_relative "stimulus_plumbers/components/progress_ring"
51
55
  require_relative "stimulus_plumbers/components/progress_meter"
56
+ require_relative "stimulus_plumbers/components/password_strength"
52
57
 
53
58
  # -- Calendar --
54
59
  require_relative "stimulus_plumbers/components/calendar"
@@ -70,7 +75,7 @@ require_relative "stimulus_plumbers/components/combobox/date/navigation"
70
75
  require_relative "stimulus_plumbers/components/combobox/dropdown"
71
76
  require_relative "stimulus_plumbers/components/combobox/typeahead"
72
77
  require_relative "stimulus_plumbers/components/combobox/time"
73
- require_relative "stimulus_plumbers/components/combobox/builder"
78
+ require_relative "stimulus_plumbers/components/combobox/config"
74
79
 
75
80
  # -- Form --
76
81
  require_relative "stimulus_plumbers/form/field"
@@ -94,3 +99,4 @@ module StimulusPlumbers
94
99
  end
95
100
 
96
101
  require_relative "stimulus_plumbers/engine" if defined?(Rails::Engine)
102
+ require_relative "stimulus_plumbers/password_strength_validator" if defined?(ActiveModel::EachValidator)
@@ -155,6 +155,14 @@
155
155
  "targets": [],
156
156
  "values": []
157
157
  },
158
+ "password-strength": {
159
+ "actions": [
160
+ "score"
161
+ ],
162
+ "listens": [],
163
+ "targets": [],
164
+ "values": []
165
+ },
158
166
  "popover": {
159
167
  "actions": [
160
168
  "close",
@@ -180,6 +188,7 @@
180
188
  "max",
181
189
  "min",
182
190
  "optimum",
191
+ "segmentMode",
183
192
  "variant"
184
193
  ]
185
194
  },
@@ -0,0 +1,38 @@
1
+ # password-strength
2
+
3
+ Live password meter and requirements checklist. Scoring is provided by the [password strength plumber](../plumber/password_strength.md).
4
+
5
+ ## Targets
6
+
7
+ | Target | Element | Description |
8
+ | ------------------------- | --------- | ------------------------------------------------------- |
9
+ | `input` | `<input>` | Password input to score |
10
+ | `rule` | `<li>` | Requirement row with `data-rule` and `data-satisfied` |
11
+ | `level` | Element | Visible, polite live strength label |
12
+ | `checkIcon` / `closeIcon` | `<svg>` | Paired rule-state icons; both are required for swapping |
13
+
14
+ ## Values and outlet
15
+
16
+ | Name | Type | Default |
17
+ | ----------------- | ---------- | --------- |
18
+ | `scorer` | String | `'rules'` |
19
+ | `rules` | Array | `[]` |
20
+ | `options` | Object | `{}` |
21
+ | `labels` | Object | `{}` |
22
+ | `announceDelay` | Number | `700` |
23
+ | `progress` outlet | Controller | — |
24
+
25
+ `score()` is wired to the input event. It updates the progress outlet immediately and debounces level-label changes.
26
+
27
+ ## Rule descriptors
28
+
29
+ The controller holds no built-in rule table — the server (or a standalone caller) supplies every rule as data via the `rules` value. Each descriptor is `{ key, label?, pattern?, min?, max? }` and passes when `min ≤ n ≤ max`, where `n` is:
30
+
31
+ - **length** (no `pattern`) — the password length.
32
+ - **count** (with `pattern`) — non-overlapping occurrences of `pattern`: `(pw.match(new RegExp(pattern, "g")) || []).length`.
33
+
34
+ Defaults: `min` `0`, `max` `Infinity`. So `{ pattern: "\\d", min: 2 }` requires ≥2 digits, and `{ pattern: "\\s", min: 0, max: 0 }` forbids whitespace.
35
+
36
+ **Portability constraint:** patterns must be single-char-consuming character classes — no anchors (`^`/`$`), lookbehind, or unicode-property escapes — so non-overlapping counts agree across the Ruby and JS regex engines.
37
+
38
+ The strength `level` is `strong` when every rule passes; otherwise the score (`satisfied / total × 100`) splits `weak` from `fine` at `options.low` (default `34`). `options` carries only these non-rule knobs.
@@ -1,6 +1,6 @@
1
1
  # Progress
2
2
 
3
- Value-driven progress indicator supporting three render variants: a linear bar, an SVG ring, and a native `<meter>`.
3
+ Value-driven progress indicator supporting four render variants: a linear bar, a segmented bar, an SVG ring, and a native `<meter>`.
4
4
 
5
5
  ## Stimulus Identifier
6
6
 
@@ -8,24 +8,25 @@ Value-driven progress indicator supporting three render variants: a linear bar,
8
8
 
9
9
  ## Targets
10
10
 
11
- | Name | Element | Purpose |
12
- | ------- | --------------------------------- | ----------------------------------------------------------------------------------- |
13
- | `fill` | `<div>` (bar) / `<circle>` (ring) | Element whose `width` (bar) or `stroke-dasharray`/`stroke-dashoffset` (ring) is set |
14
- | `meter` | `<meter>` | Present only for `variant: "meter"` — native element, attributes synced directly |
11
+ | Name | Element | Purpose |
12
+ | ------- | --------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
13
+ | `fill` | `<div>` (bar) / `<circle>` (ring) | Element whose `width` (bar) or `stroke-dasharray`/`stroke-dashoffset` (ring) is set. Segmented renders **one `fill` per segment**; the controller distributes the value across them |
14
+ | `meter` | `<meter>` | Present only for `variant: "meter"` — native element, attributes synced directly |
15
15
 
16
16
  ## Values
17
17
 
18
- | Name | Type | Default | Purpose |
19
- | ----------------------- | ------- | ------- | ------------------------------------------------------------------------- |
20
- | `variant` | String | `"bar"` | `"bar"` \| `"ring"` \| `"meter"` |
21
- | `current` | Number | `0` | Current value |
22
- | `min` | Number | `0` | Range minimum |
23
- | `max` | Number | `100` | Range maximum |
24
- | `optimum` | Number | — | Meter-only; maps to native `<meter optimum>` |
25
- | `low` | Number | — | Meter-only; maps to native `<meter low>` |
26
- | `high` | Number | — | Meter-only; maps to native `<meter high>` |
27
- | `indeterminate` | Boolean | `false` | Suppresses `aria-valuenow`; toggles the `sp-progress-indeterminate` class |
28
- | `indeterminateFraction` | Number | `0.25` | Static bar width / ring arc fraction rendered while indeterminate |
18
+ | Name | Type | Default | Purpose |
19
+ | ----------------------- | ------- | ------------ | -------------------------------------------------------------------------------------------------------------------------------------- |
20
+ | `variant` | String | `"bar"` | `"bar"` \| `"segmented"` \| `"ring"` \| `"meter"` |
21
+ | `current` | Number | `0` | Current value |
22
+ | `min` | Number | `0` | Range minimum |
23
+ | `max` | Number | `100` | Range maximum |
24
+ | `optimum` | Number | — | Meter-only; maps to native `<meter optimum>` |
25
+ | `low` | Number | — | Meter-only; maps to native `<meter low>` |
26
+ | `high` | Number | — | Meter-only; maps to native `<meter high>` |
27
+ | `indeterminate` | Boolean | `false` | Suppresses `aria-valuenow`; toggles the `sp-progress-indeterminate` class |
28
+ | `indeterminateFraction` | Number | `0.25` | Bar width / ring arc / segment chunk-width fraction rendered while indeterminate |
29
+ | `segmentMode` | String | `"discrete"` | Segmented-only. `"discrete"` lights a whole segment once progress reaches into it; `"continuous"` partially fills the boundary segment |
29
30
 
30
31
  ## Methods
31
32
 
@@ -54,6 +55,22 @@ Value-driven progress indicator supporting three render variants: a linear bar,
54
55
  <div data-progress-target="fill"></div>
55
56
  </div>
56
57
 
58
+ <!-- Segmented — one fill per segment; number of segments = number of fill targets -->
59
+ <div
60
+ role="progressbar"
61
+ data-controller="progress"
62
+ data-progress-variant-value="segmented"
63
+ data-progress-current-value="6"
64
+ data-progress-max-value="10"
65
+ >
66
+ <!-- ×5 slots → segment size 2 -->
67
+ <div aria-hidden="true"><div data-progress-target="fill"></div></div>
68
+ <div aria-hidden="true"><div data-progress-target="fill"></div></div>
69
+ <div aria-hidden="true"><div data-progress-target="fill"></div></div>
70
+ <div aria-hidden="true"><div data-progress-target="fill"></div></div>
71
+ <div aria-hidden="true"><div data-progress-target="fill"></div></div>
72
+ </div>
73
+
57
74
  <!-- Ring -->
58
75
  <svg
59
76
  role="progressbar"
@@ -558,6 +558,53 @@
558
558
  "actions": [],
559
559
  "dispatches": []
560
560
  },
561
+ "password-strength": {
562
+ "identifier": "password-strength",
563
+ "targets": [
564
+ "input",
565
+ "rule",
566
+ "level",
567
+ "checkIcon",
568
+ "closeIcon"
569
+ ],
570
+ "values": {
571
+ "scorer": {
572
+ "type": "String",
573
+ "default": "rules"
574
+ },
575
+ "rules": {
576
+ "type": "Array",
577
+ "default": []
578
+ },
579
+ "options": {
580
+ "type": "Object",
581
+ "default": {}
582
+ },
583
+ "labels": {
584
+ "type": "Object",
585
+ "default": {}
586
+ },
587
+ "announceDelay": {
588
+ "type": "Number",
589
+ "default": 700
590
+ }
591
+ },
592
+ "outlets": [
593
+ "progress"
594
+ ],
595
+ "classes": [],
596
+ "actions": [
597
+ "announce",
598
+ "constructor",
599
+ "drawIcons",
600
+ "drawRules",
601
+ "enhance",
602
+ "if",
603
+ "readValue",
604
+ "score"
605
+ ],
606
+ "dispatches": []
607
+ },
561
608
  "popover": {
562
609
  "identifier": "popover",
563
610
  "targets": [
@@ -643,6 +690,10 @@
643
690
  "type": "Number",
644
691
  "default": 0.25
645
692
  },
693
+ "segmentMode": {
694
+ "type": "String",
695
+ "default": "discrete"
696
+ },
646
697
  "optimum": {
647
698
  "type": "Number"
648
699
  },
@@ -662,6 +713,7 @@
662
713
  "renderBar",
663
714
  "renderMeter",
664
715
  "renderRing",
716
+ "renderSegmented",
665
717
  "setCircumference",
666
718
  "setValue"
667
719
  ],
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: stimulus_plumbers
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.4.13
4
+ version: 0.4.15
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ryan Chang
@@ -88,7 +88,7 @@ files:
88
88
  - lib/stimulus_plumbers/components/checklist/item.rb
89
89
  - lib/stimulus_plumbers/components/checklist/item/slots.rb
90
90
  - lib/stimulus_plumbers/components/combobox.rb
91
- - lib/stimulus_plumbers/components/combobox/builder.rb
91
+ - lib/stimulus_plumbers/components/combobox/config.rb
92
92
  - lib/stimulus_plumbers/components/combobox/date.rb
93
93
  - lib/stimulus_plumbers/components/combobox/date/navigation.rb
94
94
  - lib/stimulus_plumbers/components/combobox/date/navigator.rb
@@ -112,9 +112,11 @@ files:
112
112
  - lib/stimulus_plumbers/components/ordered_list.rb
113
113
  - lib/stimulus_plumbers/components/ordered_list/item.rb
114
114
  - lib/stimulus_plumbers/components/ordered_list/item/slots.rb
115
+ - lib/stimulus_plumbers/components/password_strength.rb
115
116
  - lib/stimulus_plumbers/components/popover.rb
116
117
  - lib/stimulus_plumbers/components/popover/panel.rb
117
118
  - lib/stimulus_plumbers/components/popover/trigger.rb
119
+ - lib/stimulus_plumbers/components/progress/shared.rb
118
120
  - lib/stimulus_plumbers/components/progress_bar.rb
119
121
  - lib/stimulus_plumbers/components/progress_meter.rb
120
122
  - lib/stimulus_plumbers/components/progress_ring.rb
@@ -138,6 +140,8 @@ files:
138
140
  - lib/stimulus_plumbers/form/fields/inputs/datetime.rb
139
141
  - lib/stimulus_plumbers/form/fields/inputs/file.rb
140
142
  - lib/stimulus_plumbers/form/fields/inputs/password.rb
143
+ - lib/stimulus_plumbers/form/fields/inputs/password/revealable.rb
144
+ - lib/stimulus_plumbers/form/fields/inputs/password/strength.rb
141
145
  - lib/stimulus_plumbers/form/fields/inputs/radio.rb
142
146
  - lib/stimulus_plumbers/form/fields/inputs/search.rb
143
147
  - lib/stimulus_plumbers/form/fields/inputs/select.rb
@@ -171,7 +175,10 @@ files:
171
175
  - lib/stimulus_plumbers/helpers/progress_helper.rb
172
176
  - lib/stimulus_plumbers/helpers/timeline_helper.rb
173
177
  - lib/stimulus_plumbers/logger.rb
178
+ - lib/stimulus_plumbers/password/requirements.rb
179
+ - lib/stimulus_plumbers/password_strength_validator.rb
174
180
  - lib/stimulus_plumbers/plumber/base.rb
181
+ - lib/stimulus_plumbers/plumber/config.rb
175
182
  - lib/stimulus_plumbers/plumber/dispatcher.rb
176
183
  - lib/stimulus_plumbers/plumber/dispatcher/callable_inspector.rb
177
184
  - lib/stimulus_plumbers/plumber/dispatcher/instance_exec.rb
@@ -215,6 +222,7 @@ files:
215
222
  - vendor/controller/docs/input-revealable.md
216
223
  - vendor/controller/docs/modal.md
217
224
  - vendor/controller/docs/panner.md
225
+ - vendor/controller/docs/password-strength.md
218
226
  - vendor/controller/docs/popover.md
219
227
  - vendor/controller/docs/progress.md
220
228
  - vendor/controller/docs/reorderable.md