stimulus_plumbers_tailwind 0.4.14 → 0.4.16

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 3fade9eb057604db9bcfaa34e4b5465436cf4121ca2fac2fc0135d8923d8fc15
4
- data.tar.gz: 55d4ca0db20ba21adeba78c644be9a0da03d5136c55f549d697a20b290a38c39
3
+ metadata.gz: 33ab72484958134862e7462abb7dccd71ee6cc386addfdc741085979514ac5c5
4
+ data.tar.gz: f3557154e6f5077fe2bebe5aacc3e1c06b23cba932cad8ce99a1d105196308d4
5
5
  SHA512:
6
- metadata.gz: e06686efbc235d53f5b6621f23595d3f234e79ad28ce67f02579a354e25db36cde73f567a1952113084507b3344677a81c4cd19657883b80786dfadd62a903f7
7
- data.tar.gz: 10406b395a531faf1ccf516168673471bf4ebe0833958e7ca1b10457c239c04bfba2556dc58d12fc3b1263b7accdb80e3500b4eb79ded11962817623ecd28c50
6
+ metadata.gz: af816ad054bb6ec34a4632bd6e24cace88339614747bb005578325946998490c472d010d267ae182b6d2c56f2168e0ed29c085410a9efa6abd1ae7d3d2171e7a
7
+ data.tar.gz: 4643a0fbe7b94fabbbdaf7c062be07ba90cc48b6c95b3e30db7e67ffb39b9a9595cf546c2a72c2faccfbe2782bf9ee0ebdc2b2f3b7b6562242cf1483a06c227c
data/CHANGELOG.md CHANGED
@@ -2,6 +2,21 @@
2
2
 
3
3
  All notable changes to this project will be documented in this file. See [conventional commits](https://www.conventionalcommits.org/) for commit guidelines.
4
4
 
5
+ ---
6
+ ## [0.4.15](https://github.com/ryancyq/stimulus-plumbers/compare/stimulus-plumbers-tailwind/v0.4.14..stimulus-plumbers-tailwind/v0.4.15) - 2026-07-23
7
+
8
+ ### Features
9
+
10
+ - password strength ([#191](https://github.com/ryancyq/stimulus-plumbers/issues/191)) - ([2f7ad55](https://github.com/ryancyq/stimulus-plumbers/commit/2f7ad550ab882225fd886956c586c0011af021fc)) - Ryan Chang
11
+ - segmented progress bar ([#192](https://github.com/ryancyq/stimulus-plumbers/issues/192)) - ([9c43461](https://github.com/ryancyq/stimulus-plumbers/commit/9c43461a262dc19a7546aadadefaf2e4e75a4acb)) - Ryan Chang
12
+
13
+ ---
14
+ ## [0.4.14](https://github.com/ryancyq/stimulus-plumbers/compare/stimulus-plumbers-tailwind/v0.4.13..stimulus-plumbers-tailwind/v0.4.14) - 2026-07-20
15
+
16
+ ### Bug Fixes
17
+
18
+ - icon schema now returns aria/data attributes from svg files ([#189](https://github.com/ryancyq/stimulus-plumbers/issues/189)) - ([ea9d079](https://github.com/ryancyq/stimulus-plumbers/commit/ea9d079d10b3f802284f9fd963fda8e9cec5f02d)) - Ryan Chang
19
+
5
20
  ---
6
21
  ## [0.4.13](https://github.com/ryancyq/stimulus-plumbers/compare/stimulus-plumbers-tailwind/v0.4.12..stimulus-plumbers-tailwind/v0.4.13) - 2026-07-20
7
22
 
@@ -1,5 +1,6 @@
1
1
  @theme {
2
- --animate-progress-slide: sp-progress-slide 1.5s ease-in-out infinite;
2
+ --sp-progress-slide-duration: 1.5s;
3
+ --animate-progress-slide: sp-progress-slide var(--sp-progress-slide-duration) ease-in-out infinite;
3
4
  }
4
5
 
5
6
  @keyframes sp-progress-slide {
@@ -7,11 +8,56 @@
7
8
  100% { transform: translateX(300%); }
8
9
  }
9
10
 
11
+ /* Segmented indeterminate: travel spans slot + chunk so the chunk clears the slot (clipped by
12
+ `overflow-hidden`) instead of parking in it, then waits its turn. */
13
+ @keyframes sp-progress-relay {
14
+ 0% { transform: translateX(-100%); }
15
+ 25% { transform: translateX(400%); }
16
+ 100% { transform: translateX(400%); }
17
+ }
18
+
19
+ /* Last slot ends the relay: chunk stops flush with the slot's far edge and fades out.
20
+ Shorter travel over a shorter window, so the glide speed is unchanged. */
21
+ @keyframes sp-progress-relay-end {
22
+ 0% { transform: translateX(-100%); opacity: 1; }
23
+ 20% { transform: translateX(300%); opacity: 1; }
24
+ 30% { transform: translateX(300%); opacity: 0; }
25
+ 100% { transform: translateX(300%); opacity: 0; }
26
+ }
27
+
10
28
  /* Ring-only; core's transition covers width, not stroke-dashoffset. */
11
29
  [data-progress-target="fill"] {
12
30
  transition: stroke-dashoffset 0.3s ease;
13
31
  }
14
32
 
33
+ /* Relay one chunk left-to-right across the segments at the bar's speed: the cycle scales with segment
34
+ count (1/0.2 = 5 slots fit the bar's 1.5s), each slot taking its turn 1/count later. The 25% glide
35
+ runs longer than that handoff — the overlap is what keeps the wave whole across the gap.
36
+ `backwards` holds a waiting slot at the first keyframe (off-screen left) so it stays hidden. */
37
+ @media (prefers-reduced-motion: no-preference) {
38
+ .sp-progress-indeterminate [aria-hidden="true"] > [data-progress-target="fill"] {
39
+ animation-name: sp-progress-relay;
40
+ animation-duration: calc(var(--sp-progress-slide-duration) / var(--sp-progress-count, 1) / 0.2);
41
+ animation-delay: calc(
42
+ var(--sp-progress-index, 0) / var(--sp-progress-count, 1) * var(--sp-progress-slide-duration)
43
+ );
44
+ /* The per-slot windows are contiguous, so a constant-speed glide reads as one continuous
45
+ wave; ease-in-out would decelerate to a stop each slot and look like a pause. */
46
+ animation-timing-function: linear;
47
+ animation-fill-mode: backwards;
48
+ }
49
+
50
+ /* Ramp the whole relay in/out at its ends only — the first slot accelerates from rest,
51
+ the last decelerates to a stop and fades; every slot between stays constant speed. */
52
+ .sp-progress-indeterminate [aria-hidden="true"]:first-child > [data-progress-target="fill"] {
53
+ animation-timing-function: ease-in;
54
+ }
55
+ .sp-progress-indeterminate [aria-hidden="true"]:last-child > [data-progress-target="fill"] {
56
+ animation-name: sp-progress-relay-end;
57
+ animation-timing-function: ease-out;
58
+ }
59
+ }
60
+
15
61
  /* Track color — kept out of the SVG so consumers can retheme it via CSS. */
16
62
  svg[role="progressbar"] .track {
17
63
  stroke: var(--sp-color-muted);
data/docs/guide.md CHANGED
@@ -12,7 +12,7 @@ bin/rails generate stimulus_plumbers:tailwind:install
12
12
 
13
13
  It re-runs automatically on `assets:precompile`/`tailwindcss:build` after that. File detection and
14
14
  the `STIMULUS_PLUMBERS_CSS_ENTRY` override are shared with the core gem — see
15
- [stimulus-plumbers-rails/docs/guide.md#css-entry-file-detection](../../stimulus-plumbers-rails/docs/guide.md#css-entry-file-detection).
15
+ `guide://component` ([CSS entry file detection](https://github.com/ryancyq/stimulus-plumbers/blob/main/stimulus-plumbers-rails/docs/guide.md#css-entry-file-detection)).
16
16
 
17
17
  ## Installed CSS files
18
18
 
@@ -27,8 +27,9 @@ an existing one. Legacy imports that point into gem directories are migrated to
27
27
  paths.
28
28
 
29
29
  Icons: pass a kebab-case name to `sp_icon` or any `icon_leading:`/`icon_trailing:` option (append
30
- `/solid` for the filled variant) — see [README.md](../README.md#icons) for aliases and the
31
- optional `heroicons` gem.
30
+ `/solid` for the filled variant) — names and aliases are in `component://icons` (`list_icons`), and
31
+ the [README](https://github.com/ryancyq/stimulus-plumbers/blob/main/stimulus-plumbers-tailwind/README.md#icons)
32
+ covers the optional `heroicons` gem.
32
33
 
33
- To implement a custom theme instead of/alongside Tailwind, see
34
- [stimulus-plumbers-rails/docs/component/theme.md](../../stimulus-plumbers-rails/docs/component/theme.md).
34
+ To implement a custom theme instead of/alongside Tailwind, see `guide://theme`
35
+ ([theme.md](https://github.com/ryancyq/stimulus-plumbers/blob/main/stimulus-plumbers-rails/docs/component/theme.md)).
@@ -2,6 +2,6 @@
2
2
 
3
3
  module StimulusPlumbers
4
4
  module Tailwind
5
- VERSION = "0.4.14"
5
+ VERSION = "0.4.16"
6
6
  end
7
7
  end
@@ -78,6 +78,59 @@ module StimulusPlumbers
78
78
  [&>div:first-child]:focus-within:ring-0
79
79
  ].freeze
80
80
 
81
+ # ── Range ─────────────────────────────────────────────────────────────
82
+ # A slider is a track and a thumb, so it takes none of INPUT's box chrome.
83
+ # WebKit has no filled-track pseudo-element: the fill is a gradient stopped at
84
+ # --sp-progress-percent (set by the progress controller). Firefox has
85
+ # ::-moz-range-progress and uses that instead.
86
+ # Must stay on one line: Tailwind scans source text, so a class split across a string
87
+ # continuation never appears contiguously and is silently dropped from the build.
88
+ # rubocop:disable Layout/LineLength
89
+ RANGE_FILL = "[&::-webkit-slider-runnable-track]:bg-[linear-gradient(to_right,var(--sp-color-primary)_0_calc(var(--sp-progress-percent,0)*1%),transparent_0)]"
90
+ # rubocop:enable Layout/LineLength
91
+
92
+ RANGE = [
93
+ "w-full appearance-none bg-transparent cursor-pointer",
94
+ "focus:outline-none",
95
+ "focus-visible:outline-none",
96
+ "focus-visible:ring-(length:--sp-focus-ring-width)",
97
+ "focus-visible:ring-(--sp-focus-ring-color)",
98
+ "disabled:opacity-50 disabled:cursor-not-allowed",
99
+ # WebKit track + thumb
100
+ "[&::-webkit-slider-runnable-track]:h-2",
101
+ "[&::-webkit-slider-runnable-track]:rounded-full",
102
+ "[&::-webkit-slider-runnable-track]:bg-(--sp-color-muted)",
103
+ RANGE_FILL,
104
+ "[&::-webkit-slider-thumb]:appearance-none",
105
+ "[&::-webkit-slider-thumb]:size-4",
106
+ "[&::-webkit-slider-thumb]:rounded-full",
107
+ "[&::-webkit-slider-thumb]:bg-(--sp-color-primary)",
108
+ # Centers a 16px thumb on an 8px track.
109
+ "[&::-webkit-slider-thumb]:-mt-1",
110
+ # Firefox track + native fill + thumb
111
+ "[&::-moz-range-track]:h-2",
112
+ "[&::-moz-range-track]:rounded-full",
113
+ "[&::-moz-range-track]:bg-(--sp-color-muted)",
114
+ "[&::-moz-range-progress]:h-2",
115
+ "[&::-moz-range-progress]:rounded-full",
116
+ "[&::-moz-range-progress]:bg-(--sp-color-primary)",
117
+ "[&::-moz-range-thumb]:size-4",
118
+ "[&::-moz-range-thumb]:border-0",
119
+ "[&::-moz-range-thumb]:rounded-full",
120
+ "[&::-moz-range-thumb]:bg-(--sp-color-primary)"
121
+ ].freeze
122
+
123
+ # The readout sits outside the input, so the input's own disabled:opacity-50 never
124
+ # reaches it — without this a disabled slider keeps a full-strength readout.
125
+ RANGE_GROUP = %w[
126
+ flex items-center gap-(--sp-space-3)
127
+ [&:has(input:disabled)>span]:opacity-50
128
+ ].freeze
129
+
130
+ # Sits beside the track, not over it — no pill background needed.
131
+ # Shares Progress::VALUE_TEXT, resolved at call time since progress.rb loads later.
132
+ RANGE_VALUE = %w[shrink-0 text-(--sp-color-fg)].freeze
133
+
81
134
  # ── Choice inputs ─────────────────────────────────────────────────────
82
135
  CHECKBOX_TYPES = {
83
136
  default: [
@@ -154,6 +207,24 @@ module StimulusPlumbers
154
207
  form_field_input_classes(floating: floating, error: error)
155
208
  end
156
209
 
210
+ # Not form_field_input_classes — a progressbar is display-only, so it takes none of the
211
+ # text-input chrome (border, padding, focus ring); the track styling comes from progress_bar.
212
+ def form_field_input_progress_classes
213
+ { classes: klasses("w-full") }
214
+ end
215
+
216
+ def form_field_input_range_classes
217
+ { classes: klasses(*RANGE) }
218
+ end
219
+
220
+ def form_field_input_range_group_classes
221
+ { classes: klasses(*RANGE_GROUP) }
222
+ end
223
+
224
+ def form_field_input_range_value_classes
225
+ { classes: klasses(*Progress::VALUE_TEXT, *RANGE_VALUE) }
226
+ end
227
+
157
228
  def form_field_input_select_classes(floating: nil, error: false)
158
229
  form_field_input_classes(floating: floating, error: error)
159
230
  end
@@ -0,0 +1,42 @@
1
+ # frozen_string_literal: true
2
+
3
+ module StimulusPlumbers
4
+ module Themes
5
+ module Tailwind
6
+ module PasswordStrength
7
+ private
8
+
9
+ def password_strength_wrapper_classes
10
+ { classes: klasses("flex", "flex-col", "gap-(--sp-space-2)") }
11
+ end
12
+
13
+ def password_strength_rules_heading_classes
14
+ { classes: klasses("text-(length:--sp-text-sm)", "text-(--sp-color-muted-fg)") }
15
+ end
16
+
17
+ def password_strength_rules_classes
18
+ { classes: klasses("flex", "flex-col", "gap-(--sp-space-1)") }
19
+ end
20
+
21
+ # State styling keys off data-satisfied (toggled client-side by the controller),
22
+ # not a server-computed flag — the server always renders the initial (unmet) state.
23
+ def password_strength_rule_classes
24
+ state = [
25
+ "text-(--sp-color-muted-fg)",
26
+ "data-[satisfied=true]:text-(--sp-color-success)",
27
+ "data-[satisfied=true]:line-through"
28
+ ]
29
+ { classes: klasses("flex", "items-center", "gap-(--sp-space-1)", *state) }
30
+ end
31
+
32
+ def password_strength_rule_icon_classes
33
+ { classes: klasses("size-(--sp-icon-sm)", "shrink-0") }
34
+ end
35
+
36
+ def password_strength_level_classes
37
+ { classes: klasses("text-(length:--sp-text-base)", "font-semibold") }
38
+ end
39
+ end
40
+ end
41
+ end
42
+ end
@@ -5,16 +5,65 @@ module StimulusPlumbers
5
5
  module Tailwind
6
6
  module Progress
7
7
  BAR = %w[
8
- relative w-full h-2 overflow-hidden rounded-full
8
+ relative w-full overflow-hidden rounded-full
9
9
  bg-(--sp-color-muted)
10
10
  ].freeze
11
11
 
12
- BAR_FILL = %w[
12
+ BAR_HEIGHTS = { false => "h-2", true => "h-5" }.freeze
13
+
14
+ # tabular-nums so the readout doesn't jitter as digits change under a drag.
15
+ VALUE_TEXT = %w[text-xs font-medium leading-none tabular-nums].freeze
16
+
17
+ # Row wrapper for an outside readout — the track shrinks to leave room for the text.
18
+ BAR_GROUP = %w[flex w-full items-center gap-(--sp-space-2)].freeze
19
+
20
+ # Clipped to the glyphs, this paints primary-fg up to the fill edge and fg past it, so the
21
+ # digits split rather than sit on a pill — neither color alone clears AA over both. The
22
+ # edge is --sp-progress-percent (set by the progress controller), 0 until it connects.
23
+ # Must stay on one line: Tailwind scans source text, so a class split across a string
24
+ # continuation or interpolation never appears contiguously and is silently dropped.
25
+ # rubocop:disable Layout/LineLength
26
+ BAR_VALUE_SPLIT = "bg-[linear-gradient(to_right,var(--sp-color-primary-fg)_0_calc(var(--sp-progress-percent,0)*1%),var(--sp-color-fg)_0)]"
27
+ # rubocop:enable Layout/LineLength
28
+
29
+ # Spans the track so the gradient's coordinates are the track's.
30
+ BAR_VALUE = [
31
+ *VALUE_TEXT,
32
+ "absolute inset-x-0 top-1/2 -translate-y-1/2 text-center pointer-events-none",
33
+ BAR_VALUE_SPLIT,
34
+ "bg-clip-text [-webkit-background-clip:text] text-transparent"
35
+ ].freeze
36
+
37
+ # Beside the track it never sits over the fill, so it needs no pill.
38
+ BAR_VALUE_OUTSIDE = [*VALUE_TEXT, "shrink-0 text-(--sp-color-primary)"].freeze
39
+
40
+ # `data-intent` (set per-segment by a ramp) overrides the default primary fill color.
41
+ FILL_BASE = %w[
13
42
  h-full rounded-full bg-(--sp-color-primary)
43
+ [&[data-intent=danger]]:bg-(--sp-color-destructive)
44
+ [&[data-intent=warning]]:bg-(--sp-color-warning)
45
+ [&[data-intent=success]]:bg-(--sp-color-success)
46
+ ].freeze
47
+
48
+ # animations.css renames a slot fill's keyframes but reads iteration-count off this.
49
+ FILL_INDETERMINATE = %w[
14
50
  [.sp-progress-indeterminate_&]:animate-progress-slide
15
51
  [.sp-progress-indeterminate_&]:motion-reduce:animate-none
16
52
  ].freeze
17
53
 
54
+ BAR_FILL = [*FILL_BASE, *FILL_INDETERMINATE].freeze
55
+
56
+ # Row of equal-width slots; each slot is its own track with a SEGMENT_FILL inside.
57
+ SEGMENT_GROUP = %w[flex w-full gap-(--sp-space-1)].freeze
58
+
59
+ SEGMENT = %w[
60
+ flex-1 h-2 overflow-hidden rounded-full
61
+ bg-(--sp-color-muted)
62
+ ].freeze
63
+
64
+ # Separate key so a theme can restyle a slot's chunk without touching the bar's.
65
+ SEGMENT_FILL = [*FILL_BASE, *FILL_INDETERMINATE].freeze
66
+
18
67
  # Circle stroke/fill live in icons/customs/progress-ring.svg — @source never scans
19
68
  # .svg files, so Tailwind classes there are inert.
20
69
  # Indeterminate class and utility land on this same svg, so this needs the compound
@@ -24,6 +73,8 @@ module StimulusPlumbers
24
73
  [&.sp-progress-indeterminate]:animate-spin
25
74
  ].freeze
26
75
 
76
+ RING_SIZES = { sm: "size-8", md: "size-12", lg: "size-16" }.freeze
77
+
27
78
  METER = %w[
28
79
  w-full h-2 rounded-full
29
80
  [&::-webkit-meter-bar]:rounded-full [&::-webkit-meter-bar]:bg-(--sp-color-muted)
@@ -35,16 +86,40 @@ module StimulusPlumbers
35
86
 
36
87
  private
37
88
 
38
- def progress_bar_classes
39
- { classes: klasses(*BAR) }
89
+ def progress_bar_classes(labelled: false)
90
+ { classes: klasses(*BAR, BAR_HEIGHTS.fetch(labelled)) }
91
+ end
92
+
93
+ def progress_bar_group_classes
94
+ { classes: klasses(*BAR_GROUP) }
95
+ end
96
+
97
+ def progress_bar_value_classes
98
+ { classes: klasses(*BAR_VALUE) }
99
+ end
100
+
101
+ def progress_bar_value_outside_classes
102
+ { classes: klasses(*BAR_VALUE_OUTSIDE) }
40
103
  end
41
104
 
42
105
  def progress_bar_fill_classes
43
106
  { classes: klasses(*BAR_FILL) }
44
107
  end
45
108
 
46
- def progress_ring_classes
47
- { classes: klasses(*RING) }
109
+ def progress_segment_group_classes
110
+ { classes: klasses(*SEGMENT_GROUP) }
111
+ end
112
+
113
+ def progress_segment_classes
114
+ { classes: klasses(*SEGMENT) }
115
+ end
116
+
117
+ def progress_segment_fill_classes
118
+ { classes: klasses(*SEGMENT_FILL) }
119
+ end
120
+
121
+ def progress_ring_classes(size: nil)
122
+ { classes: klasses(*RING, *Array(RING_SIZES[size])) }
48
123
  end
49
124
 
50
125
  def progress_meter_classes
@@ -15,6 +15,7 @@ require_relative "tailwind/form/field"
15
15
  require_relative "tailwind/form/code"
16
16
  require_relative "tailwind/form/credit_card"
17
17
  require_relative "tailwind/form/input"
18
+ require_relative "tailwind/password_strength"
18
19
  require_relative "tailwind/icon"
19
20
  require_relative "tailwind/indicator"
20
21
  require_relative "tailwind/layout"
@@ -39,6 +40,7 @@ module StimulusPlumbers
39
40
  include Tailwind::Form::Code
40
41
  include Tailwind::Form::CreditCard
41
42
  include Tailwind::Form::Input
43
+ include Tailwind::PasswordStrength
42
44
  include Tailwind::Icon
43
45
  include Tailwind::Indicator
44
46
  include Tailwind::Layout
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: stimulus_plumbers_tailwind
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.4.14
4
+ version: 0.4.16
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ryan Chang
@@ -712,6 +712,7 @@ files:
712
712
  - lib/stimulus_plumbers/themes/tailwind/link.rb
713
713
  - lib/stimulus_plumbers/themes/tailwind/list.rb
714
714
  - lib/stimulus_plumbers/themes/tailwind/ordered_list.rb
715
+ - lib/stimulus_plumbers/themes/tailwind/password_strength.rb
715
716
  - lib/stimulus_plumbers/themes/tailwind/progress.rb
716
717
  - lib/stimulus_plumbers/themes/tailwind/timeline.rb
717
718
  - lib/stimulus_plumbers/themes/tailwind/timeline/group.rb