stimulus_plumbers_tailwind 0.4.0 → 0.4.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: f14f719e9c94e67c1b76669ea4a0691c7929e9a2b7df04fda692ce3ea430c4bc
4
- data.tar.gz: 161c3622b129cbcf3ee49bc304319c691cf09c8c754a01646bc608480b391029
3
+ metadata.gz: 9eb6bbfe958bd425b443843724ef2b3a66041f04fe40ec4b041a72accd9ec497
4
+ data.tar.gz: f1928462ed5485e7560a1993e72aeddbd90dd734db280703ae50e751bfcb6306
5
5
  SHA512:
6
- metadata.gz: 606d07453d71bc70cd71560c47ee12a028fbe4ab5ef3150d52024d61eef561f263c12221c73ed8689f56119b8f5b155099bad4526435f3614550b23f2934628c
7
- data.tar.gz: c4d45c72794f1c0df3310e30f5a95cb3bc3c204c1298eca5c916f645fb530d1bfb4d5ee3ff24c828290ba6e6a75e5980e4d20853eae19b1692ee64007303d60f
6
+ metadata.gz: ce4edf07b1b20042b73e67c4d16d86eb6213e0e08a3fdb2049a362c4042941fe7672b5503e185da78c4e85394a4592e7a51971fcfca01802c14d4df5c2cf4bad
7
+ data.tar.gz: 625987458573abbe7ab612323c81ce300b2ac993347e6af4903e1a034b35c7153a81d716695a79531c38578d78f0884feddfe15655b0e252cbccc0f254d05ae5
data/CHANGELOG.md CHANGED
@@ -2,6 +2,46 @@
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.3](https://github.com/ryancyq/stimulus-plumbers/compare/stimulus-plumbers-tailwind/v0.4.2..stimulus-plumbers-tailwind/v0.4.3) - 2026-06-30
7
+
8
+ ### Bug Fixes
9
+
10
+ - tailwind generator ([#149](https://github.com/ryancyq/stimulus-plumbers/issues/149)) - ([9dafae0](https://github.com/ryancyq/stimulus-plumbers/commit/9dafae03b5d49fb543d08f84cdb718d944dce49f)) - Ryan Chang
11
+
12
+ ---
13
+ ## [0.4.2](https://github.com/ryancyq/stimulus-plumbers/compare/stimulus-plumbers-tailwind/v0.4.0..stimulus-plumbers-tailwind/v0.4.2) - 2026-06-30
14
+
15
+ ### Bug Fixes
16
+
17
+ - form submit button style ([#127](https://github.com/ryancyq/stimulus-plumbers/issues/127)) - ([2bbc73f](https://github.com/ryancyq/stimulus-plumbers/commit/2bbc73f15b7ffa2d9d8f87991adead33fab8156e)) - Ryan Chang
18
+ - various component styles ([#128](https://github.com/ryancyq/stimulus-plumbers/issues/128)) - ([011cc69](https://github.com/ryancyq/stimulus-plumbers/commit/011cc69bb6df3770949564521cdf949493d028cc)) - Ryan Chang
19
+ - use generic icon in core gem then provide alias in tailwind gem ([#129](https://github.com/ryancyq/stimulus-plumbers/issues/129)) - ([5c87d0d](https://github.com/ryancyq/stimulus-plumbers/commit/5c87d0da0c012652a3afa5aa8345b58d03e6ce5b)) - Ryan Chang
20
+ - combobox time ([#130](https://github.com/ryancyq/stimulus-plumbers/issues/130)) - ([ff5d968](https://github.com/ryancyq/stimulus-plumbers/commit/ff5d968da34fc723b0112a791bd95ef43f2b1640)) - Ryan Chang
21
+ - extract img avatar building block ([#132](https://github.com/ryancyq/stimulus-plumbers/issues/132)) - ([c3808b8](https://github.com/ryancyq/stimulus-plumbers/commit/c3808b8df38eecef940b51dab29f50bc815b4e74)) - Ryan Chang
22
+ - update floating style to label/input/group ([#135](https://github.com/ryancyq/stimulus-plumbers/issues/135)) - ([3947f38](https://github.com/ryancyq/stimulus-plumbers/commit/3947f38467e0a498fe51101d1859a573db93349f)) - Ryan Chang
23
+ - accessibility + plumber helpers ([#136](https://github.com/ryancyq/stimulus-plumbers/issues/136)) - ([e84053d](https://github.com/ryancyq/stimulus-plumbers/commit/e84053d43db4726c3704d459a0464f70529fff8b)) - Ryan Chang
24
+ - calendar disabled + out of range ([#148](https://github.com/ryancyq/stimulus-plumbers/issues/148)) - ([7bd1ca2](https://github.com/ryancyq/stimulus-plumbers/commit/7bd1ca21af1b982cf7df9460e0ba1c9e78866a87)) - Ryan Chang
25
+
26
+ ### Dependencies
27
+
28
+ - **(deps-dev)** bump @playwright/test in /stimulus-plumbers-tailwind ([#147](https://github.com/ryancyq/stimulus-plumbers/issues/147)) - ([941634d](https://github.com/ryancyq/stimulus-plumbers/commit/941634de18e2accc39f926258cb3d1b2534d11dc)) - dependabot[bot]
29
+ - **(deps-dev)** bump prettier in /stimulus-plumbers-tailwind ([#146](https://github.com/ryancyq/stimulus-plumbers/issues/146)) - ([570c8ff](https://github.com/ryancyq/stimulus-plumbers/commit/570c8ff7630039bdbdc6e3d89c6a181bbc706dd8)) - dependabot[bot]
30
+
31
+ ### Documentation
32
+
33
+ - update readme and component doc ([#134](https://github.com/ryancyq/stimulus-plumbers/issues/134)) - ([3e5f462](https://github.com/ryancyq/stimulus-plumbers/commit/3e5f4621c4fbf142af061659cfbb8cd3e99fd093)) - Ryan Chang
34
+ - update component documentation - ([89ecb78](https://github.com/ryancyq/stimulus-plumbers/commit/89ecb786d88eed66ab925921ac182aa84560207d)) - Ryan Chang
35
+
36
+ ### Features
37
+
38
+ - calendar redesign ([#133](https://github.com/ryancyq/stimulus-plumbers/issues/133)) - ([e19df95](https://github.com/ryancyq/stimulus-plumbers/commit/e19df95f3814b3d947142722ff0295f1bdcef6b3)) - Ryan Chang
39
+
40
+ ### Tests
41
+
42
+ - update sandbox view and spec coverage ([#122](https://github.com/ryancyq/stimulus-plumbers/issues/122)) - ([0fd3381](https://github.com/ryancyq/stimulus-plumbers/commit/0fd33817325070c29ffed82d37843b4c4be3e911)) - Ryan Chang
43
+ - update collection radio locator - ([f0fa9e8](https://github.com/ryancyq/stimulus-plumbers/commit/f0fa9e85bc0b835b3adc46f5dc406a8bdedbeefe)) - Ryan Chang
44
+
5
45
  ---
6
46
  ## [0.4.0](https://github.com/ryancyq/stimulus-plumbers/compare/stimulus-plumbers-tailwind/v0.3.3..stimulus-plumbers-tailwind/v0.4.0) - 2026-06-14
7
47
 
data/README.md CHANGED
@@ -27,18 +27,34 @@ Activate the theme in an initializer or `config/application.rb`:
27
27
 
28
28
  ```ruby
29
29
  StimulusPlumbers.configure do |config|
30
- config.theme = :tailwind
30
+ config.theme.use(:tailwind)
31
31
  end
32
32
  ```
33
33
 
34
- Tell Tailwind to scan the gem's lib files so component class names are included in the generated CSS. Add an `@source` directive pointing at the gem's installed path:
34
+ Run the install generator once to inject the required `@source` directive into your Tailwind CSS entry file:
35
35
 
36
- ```css
37
- @import "tailwindcss";
38
- @source "/path/to/gems/stimulus_plumbers_tailwind-VERSION/lib/**/*.rb";
36
+ ```bash
37
+ bin/rails generate stimulus_plumbers_tailwind:install
39
38
  ```
40
39
 
41
- Use `bundle show stimulus_plumbers_tailwind` to get the exact installed path.
40
+ The generator checks these files in order:
41
+
42
+ - `app/assets/stylesheets/application.tailwind.css`
43
+ - `app/assets/stylesheets/application.css`
44
+ - `app/javascript/entrypoints/application.css`
45
+
46
+ Override the detected file for both the generator and rake task with `TAILWIND_CSS_FILE=/path/to/entry.css`.
47
+
48
+ After the initial install, the `@source` path is kept current automatically — no manual re-run needed after `bundle update`. The engine hooks `stimulus_plumbers_tailwind:install` as a prerequisite of:
49
+
50
+ - `assets:precompile` (Sprockets and Propshaft both define this task)
51
+ - `tailwindcss:build` (when `tailwindcss-rails` is present)
52
+
53
+ To trigger an update manually without a full compile (useful for debugging or after `bundle update`):
54
+
55
+ ```bash
56
+ bin/rails stimulus_plumbers_tailwind:install
57
+ ```
42
58
 
43
59
  ## Theming
44
60
 
@@ -46,7 +62,6 @@ Use `bundle show stimulus_plumbers_tailwind` to get the exact installed path.
46
62
 
47
63
  | Module | Components |
48
64
  |--------|------------|
49
- | `Tailwind::ActionList` | Action list, menu items |
50
65
  | `Tailwind::Avatar` | Avatar |
51
66
  | `Tailwind::Button` | Button |
52
67
  | `Tailwind::Calendar` | Calendar grid, date picker |
@@ -55,6 +70,9 @@ Use `bundle show stimulus_plumbers_tailwind` to get the exact installed path.
55
70
  | `Tailwind::Form` | Form fields, labels, errors |
56
71
  | `Tailwind::Icon` | Icon (SVG rendering, icon registry) |
57
72
  | `Tailwind::Layout` | Layout primitives |
73
+ | `Tailwind::Link` | Link |
74
+ | `Tailwind::List` | List |
75
+ | `Tailwind::Timeline` | Timeline |
58
76
 
59
77
  Custom themes can subclass `TailwindTheme` to override individual methods, or subclass `StimulusPlumbers::Themes::Base` directly.
60
78
 
@@ -85,8 +103,8 @@ bundle install
85
103
  npm install
86
104
 
87
105
  bundle exec rake test:unit # unit tests
88
- npm run test:snapshots # visual snapshot tests (Playwright)
89
- npm run test:snapshots:update # regenerate baseline screenshots
106
+ node --run test:snapshots # visual snapshot tests (Playwright)
107
+ node --run test:snapshots:update # regenerate baseline screenshots
90
108
  bundle exec rake rubocop # lint
91
109
  bundle exec rake coverage # run tests with coverage + collate report
92
110
  ```
@@ -0,0 +1,78 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "rails/generators"
4
+
5
+ module StimulusPlumbersTailwind
6
+ module Generators
7
+ class InstallGenerator < Rails::Generators::Base
8
+ GEM_NAME = "stimulus_plumbers_tailwind"
9
+ TAILWIND_CSS_FILE = "TAILWIND_CSS_FILE"
10
+ CSS_CANDIDATES = %w[
11
+ app/assets/stylesheets/application.tailwind.css
12
+ app/assets/stylesheets/application.css
13
+ app/javascript/entrypoints/application.css
14
+ ].freeze
15
+
16
+ def install
17
+ css_file = entry_css_file
18
+ return warn_entry_css_not_found unless css_file
19
+
20
+ apply_edit(css_file)
21
+ end
22
+
23
+ private
24
+
25
+ def warn_entry_css_not_found
26
+ tried = CSS_CANDIDATES.map { |c| File.join(destination_root, c) }
27
+ tried.unshift(File.expand_path(ENV[TAILWIND_CSS_FILE])) if ENV[TAILWIND_CSS_FILE]
28
+ say "Could not find a Tailwind CSS entry file. Tried: #{tried.join(", ")}. " \
29
+ "Set #{TAILWIND_CSS_FILE}=/path/to/entry.css and re-run.",
30
+ :red
31
+ end
32
+
33
+ def apply_edit(css_file)
34
+ content = File.read(css_file)
35
+ new_content, status = content_edit(content, source_directive)
36
+
37
+ if new_content
38
+ File.write(css_file, new_content)
39
+ say_status status, relative_to_destination(css_file), :green
40
+ else
41
+ say_status :identical, relative_to_destination(css_file)
42
+ end
43
+ end
44
+
45
+ def content_edit(content, source_line)
46
+ if content.include?(source_line)
47
+ nil
48
+ elsif (existing = content.match(%r{@source "[^"]*#{Regexp.escape(GEM_NAME)}[^"]*";}))
49
+ [content.sub(existing[0], source_line), :update]
50
+ elsif (import_line = content.match(%r{@import "tailwindcss"[^;]*;}))
51
+ [content.sub(import_line[0], "#{import_line[0]}\n#{source_line}"), :insert]
52
+ else
53
+ ["#{content.rstrip}\n#{source_line}\n", :append]
54
+ end
55
+ end
56
+
57
+ def source_directive
58
+ spec = Gem.loaded_specs[GEM_NAME]
59
+ %(@source "#{spec.gem_dir}/lib/**/*.rb";)
60
+ end
61
+
62
+ def entry_css_file
63
+ if ENV[TAILWIND_CSS_FILE]
64
+ path = File.expand_path(ENV[TAILWIND_CSS_FILE])
65
+ return path if File.exist?(path)
66
+ end
67
+
68
+ CSS_CANDIDATES
69
+ .map { |c| File.join(destination_root, c) }
70
+ .find { |f| File.exist?(f) }
71
+ end
72
+
73
+ def relative_to_destination(path)
74
+ path.delete_prefix("#{destination_root}/")
75
+ end
76
+ end
77
+ end
78
+ end
@@ -4,6 +4,18 @@ module StimulusPlumbers
4
4
  module Themes
5
5
  module Tailwind
6
6
  module Avatar
7
+ BASE = %w[
8
+ rounded-(--sp-radius-full)
9
+ overflow-hidden
10
+ inline-flex items-center justify-center
11
+ ].freeze
12
+
13
+ SIZES = {
14
+ sm: "size-(--sp-avatar-size-sm)",
15
+ md: "size-(--sp-avatar-size-md)",
16
+ lg: "size-(--sp-avatar-size-lg)"
17
+ }.freeze
18
+
7
19
  VARIANTS = {
8
20
  amber: "text-white bg-amber-600",
9
21
  lime: "text-white bg-lime-600",
@@ -19,18 +31,6 @@ module StimulusPlumbers
19
31
  blue: "text-white bg-blue-600"
20
32
  }.freeze
21
33
 
22
- SIZES = {
23
- sm: "size-(--sp-icon-size)",
24
- md: "size-(--sp-avatar-size)",
25
- lg: "size-(--sp-avatar-size-lg)"
26
- }.freeze
27
-
28
- BASE = %w[
29
- rounded-(--sp-radius-full)
30
- overflow-hidden
31
- inline-flex items-center justify-center
32
- ].freeze
33
-
34
34
  def avatar_variants
35
35
  VARIANTS
36
36
  end
@@ -4,6 +4,25 @@ module StimulusPlumbers
4
4
  module Themes
5
5
  module Tailwind
6
6
  module Button
7
+ # ── Structure ─────────────────────────────────────────────────────────
8
+ BASE = [
9
+ *Control::BASE,
10
+ "whitespace-nowrap",
11
+ "focus-visible:ring-(--btn-ring)"
12
+ ].freeze
13
+
14
+ LAYOUT = %w[
15
+ inline-flex items-center justify-center gap-(--sp-space-2)
16
+ [&:not(:has(>span))]:aspect-square
17
+ [&:not(:has(>span))]:px-0
18
+ ].freeze
19
+
20
+ CARD = %w[
21
+ inline-flex justify-start items-center flex-1 gap-(--sp-space-3) p-(--sp-space-4)
22
+ [&>:last-child:not(:first-child)]:ml-auto
23
+ ].freeze
24
+
25
+ # ── Color tokens ──────────────────────────────────────────────────────
7
26
  VARIANTS = {
8
27
  primary: %w[
9
28
  [--btn-bg:var(--sp-color-primary)]
@@ -56,6 +75,7 @@ module StimulusPlumbers
56
75
  ].freeze
57
76
  }.freeze
58
77
 
78
+ # ── Type styles ───────────────────────────────────────────────────────
59
79
  TYPES = {
60
80
  default: %w[
61
81
  rounded-(--sp-radius-md)
@@ -67,13 +87,13 @@ module StimulusPlumbers
67
87
  rounded-(--sp-radius-md)
68
88
  bg-(--sp-color-bg) text-(--btn-accent)
69
89
  border border-(--btn-border)
70
- hover:bg-(--btn-bg)/10
90
+ hover:bg-(--btn-accent)/10
71
91
  ].freeze,
72
92
  ghost: %w[
73
93
  rounded-(--sp-radius-md)
74
94
  bg-transparent text-(--btn-accent)
75
95
  border border-transparent
76
- hover:bg-(--btn-bg)/10
96
+ hover:bg-(--btn-accent)/10
77
97
  ].freeze,
78
98
  fab: %w[
79
99
  rounded-(--sp-radius-full)
@@ -93,16 +113,17 @@ module StimulusPlumbers
93
113
  rounded-(--sp-radius-md)
94
114
  bg-(--sp-color-bg) text-(--btn-accent)
95
115
  border border-dashed border-(--btn-border)
96
- hover:bg-(--btn-bg)/10
116
+ hover:bg-(--btn-accent)/10
97
117
  ].freeze,
98
118
  card: %w[
99
119
  rounded-(--sp-radius-md)
100
120
  bg-(--sp-color-bg) text-(--btn-accent)
101
121
  border border-(--btn-border) shadow-(--sp-shadow-xs)
102
- hover:bg-(--btn-bg)/10
122
+ hover:bg-(--btn-accent)/10
103
123
  ].freeze
104
124
  }.freeze
105
125
 
126
+ # ── Sizes ─────────────────────────────────────────────────────────────
106
127
  SIZES = {
107
128
  xs: %w[h-7 px-(--sp-space-2) text-(length:--sp-text-xs)].freeze,
108
129
  sm: %w[h-8 px-(--sp-space-3) text-(length:--sp-text-sm)].freeze,
@@ -111,23 +132,6 @@ module StimulusPlumbers
111
132
  xl: %w[h-14 px-(--sp-space-6) text-(length:--sp-text-lg)].freeze
112
133
  }.freeze
113
134
 
114
- BASE = [
115
- *Control::BASE,
116
- "whitespace-nowrap",
117
- "focus-visible:ring-(--btn-ring)"
118
- ].freeze
119
-
120
- LAYOUT = %w[
121
- inline-flex items-center justify-center gap-(--sp-space-2)
122
- [&:not(:has(>span))]:aspect-square
123
- [&:not(:has(>span))]:px-0
124
- ].freeze
125
-
126
- CARD = %w[
127
- inline-flex justify-start items-center flex-1 gap-(--sp-space-3) p-(--sp-space-4)
128
- [&>:last-child:not(:first-child)]:ml-auto
129
- ].freeze
130
-
131
135
  private
132
136
 
133
137
  def button_classes(type: :default, variant: :primary, size: :md)
@@ -143,7 +147,7 @@ module StimulusPlumbers
143
147
  end
144
148
 
145
149
  def button_icon_classes
146
- { classes: klasses("size-(--sp-control-size)", "stroke-current") }
150
+ { classes: klasses("size-(--sp-icon-size-sm)", "stroke-current") }
147
151
  end
148
152
  end
149
153
  end
@@ -4,7 +4,7 @@ module StimulusPlumbers
4
4
  module Themes
5
5
  module Tailwind
6
6
  module Calendar
7
- GRID = %w[w-full].freeze
7
+ GRID = [].freeze
8
8
 
9
9
  DAYS_OF_WEEK = %w[
10
10
  grid grid-cols-7 text-center text-(length:--sp-text-xs)
@@ -16,41 +16,52 @@ module StimulusPlumbers
16
16
  DAY = %w[
17
17
  size-(--sp-calendar-day-size) rounded-(--sp-radius-md)
18
18
  flex items-center justify-center text-(length:--sp-text-sm)
19
- hover:bg-(--sp-color-muted) cursor-pointer
19
+ [&:is(button)]:hover:bg-(--sp-color-muted) [&:is(button)]:cursor-pointer
20
20
  aria-[current=date]:font-bold
21
21
  aria-selected:bg-(--sp-color-primary)
22
22
  aria-selected:text-(--sp-color-primary-fg)
23
23
  aria-selected:hover:bg-(--sp-color-primary)/90
24
24
  aria-[hidden=true]:pointer-events-none
25
- aria-[hidden=true]:hover:bg-transparent
25
+ aria-[disabled=true]:text-(--sp-color-muted-fg)
26
+ aria-[disabled=true]:opacity-40
27
+ aria-[disabled=true]:pointer-events-none
28
+ disabled:text-(--sp-color-muted-fg)
29
+ disabled:opacity-40
30
+ disabled:pointer-events-none
26
31
  ].freeze
27
32
 
28
- QUARTER_GRID = %w[grid grid-cols-4].freeze
33
+ QUARTER_GRID = %w[grid grid-cols-4 gap-(--sp-space-1)].freeze
29
34
 
30
35
  MONTHS_OF_YEAR = "contents"
31
36
 
32
37
  MONTH = %w[
33
38
  rounded-(--sp-radius-md) flex items-center justify-center
34
- text-(length:--sp-text-sm) h-10 flex-1
39
+ text-(length:--sp-text-sm) h-10 flex-1 px-(--sp-space-2)
35
40
  hover:bg-(--sp-color-muted) cursor-pointer
36
41
  aria-selected:bg-(--sp-color-primary)
37
42
  aria-selected:text-(--sp-color-primary-fg)
38
43
  aria-selected:hover:bg-(--sp-color-primary)/90
39
- aria-disabled:pointer-events-none aria-disabled:text-(--sp-color-disabled-fg)
40
44
  aria-[current=month]:font-bold
45
+ aria-[disabled=true]:text-(--sp-color-muted-fg)
46
+ aria-[disabled=true]:opacity-40
47
+ aria-[disabled=true]:pointer-events-none
48
+ aria-[disabled=true]:hover:bg-transparent
41
49
  ].freeze
42
50
 
43
51
  YEARS_OF_DECADE = "contents"
44
52
 
45
53
  YEAR = %w[
46
54
  rounded-(--sp-radius-md) flex items-center justify-center
47
- text-(length:--sp-text-sm) h-10 flex-1
55
+ text-(length:--sp-text-sm) h-10 flex-1 px-(--sp-space-2)
48
56
  hover:bg-(--sp-color-muted) cursor-pointer
49
57
  aria-selected:bg-(--sp-color-primary)
50
58
  aria-selected:text-(--sp-color-primary-fg)
51
59
  aria-selected:hover:bg-(--sp-color-primary)/90
52
- aria-disabled:pointer-events-none aria-disabled:text-(--sp-color-disabled-fg)
53
60
  aria-[current=year]:font-bold
61
+ aria-[disabled=true]:text-(--sp-color-muted-fg)
62
+ aria-[disabled=true]:opacity-40
63
+ aria-[disabled=true]:pointer-events-none
64
+ aria-[disabled=true]:hover:bg-transparent
54
65
  ].freeze
55
66
 
56
67
  private
@@ -80,21 +91,13 @@ module StimulusPlumbers
80
91
  end
81
92
 
82
93
  def calendar_day_classes(outside: false, **)
83
- {
84
- classes: klasses(
85
- *DAY,
86
- *(outside ? %w[text-(--sp-color-disabled-fg)] : [])
87
- )
88
- }
94
+ extra = outside ? %w[text-(--sp-color-muted-fg)] : []
95
+ { classes: klasses(*DAY, *extra) }
89
96
  end
90
97
 
91
- def calendar_month_classes(**)
92
- { classes: klasses(*MONTH) }
93
- end
98
+ def calendar_month_classes(**) = { classes: klasses(*MONTH) }
94
99
 
95
- def calendar_year_classes(**)
96
- { classes: klasses(*YEAR) }
97
- end
100
+ def calendar_year_classes(**) = { classes: klasses(*YEAR) }
98
101
 
99
102
  def calendar_quarter_grid_classes
100
103
  { classes: klasses(*QUARTER_GRID) }
@@ -5,6 +5,7 @@ module StimulusPlumbers
5
5
  module Tailwind
6
6
  module Card
7
7
  BASE = %w[
8
+ flex flex-col
8
9
  rounded-(--sp-radius-md) border border-(--card-ring)
9
10
  bg-(--sp-color-bg) shadow-(--sp-shadow-xs)
10
11
  ].freeze
@@ -21,7 +22,7 @@ module StimulusPlumbers
21
22
 
22
23
  HEADER_BASE = %w[
23
24
  flex items-center gap-(--sp-space-3)
24
- px-(--sp-space-6) pt-(--sp-space-6)
25
+ px-(--sp-space-6) py-(--sp-space-6)
25
26
  ].freeze
26
27
 
27
28
  ICON_BASE = %w[
@@ -33,12 +34,10 @@ module StimulusPlumbers
33
34
  ].freeze
34
35
 
35
36
  BODY_BASE = %w[
36
- px-(--sp-space-6) pt-(--sp-space-3)
37
+ px-(--sp-space-6) py-(--sp-space-3)
37
38
  ].freeze
38
39
 
39
- ACTION_BASE = %w[
40
- px-(--sp-space-6) pb-(--sp-space-6) pt-(--sp-space-4)
41
- ].freeze
40
+ ACTION_BASE = %w[w-full justify-start].freeze
42
41
 
43
42
  private
44
43
 
@@ -4,8 +4,13 @@ module StimulusPlumbers
4
4
  module Themes
5
5
  module Tailwind
6
6
  module Combobox
7
+ # ── Container / popover ───────────────────────────────────────────────
8
+ CONTAINER = %w[relative].freeze
9
+ POPOVER = %w[absolute top-full left-0 min-w-full].freeze
10
+
11
+ # ── Trigger ───────────────────────────────────────────────────────────
7
12
  TRIGGER = %w[
8
- w-full rounded-(--sp-radius-md) border border-(--sp-color-muted-fg)
13
+ w-full rounded-(--sp-radius-md) border border-(--sp-color-muted-fg) hover:border-(--sp-color-fg)
9
14
  px-(--sp-space-3) py-(--sp-space-2)
10
15
  text-(length:--sp-text-sm) text-(--sp-color-fg) bg-(--sp-color-bg)
11
16
  focus:outline-none focus:ring-2 focus:ring-(--sp-focus-ring-color)
@@ -13,7 +18,7 @@ module StimulusPlumbers
13
18
 
14
19
  TRIGGER_GROUP = %w[
15
20
  flex items-center gap-(--sp-space-2) overflow-hidden
16
- rounded-(--sp-radius-md) border border-(--sp-color-muted-fg) bg-(--sp-color-bg)
21
+ rounded-(--sp-radius-md) border border-(--sp-color-muted-fg) hover:border-(--sp-color-fg) bg-(--sp-color-bg)
17
22
  px-(--sp-space-3) py-(--sp-space-2)
18
23
  focus-within:outline-none focus-within:ring-2 focus-within:ring-(--sp-focus-ring-color)
19
24
  [&>input]:border-0 [&>input]:rounded-none
@@ -22,8 +27,9 @@ module StimulusPlumbers
22
27
  [&>input]:focus:ring-0
23
28
  ].freeze
24
29
 
30
+ # ── Listbox / options ─────────────────────────────────────────────────
25
31
  LISTBOX = %w[
26
- py-(--sp-space-1) overflow-y-auto max-h-60
32
+ py-(--sp-space-1) overflow-y-auto max-h-60 min-h-(--sp-space-6)
27
33
  ].freeze
28
34
 
29
35
  OPTION_BASE = %w[
@@ -44,6 +50,7 @@ module StimulusPlumbers
44
50
 
45
51
  OPTION_GROUP = %w[py-(--sp-space-1)].freeze
46
52
 
53
+ # ── Typeahead states ──────────────────────────────────────────────────
47
54
  TYPEAHEAD_LOADING = %w[
48
55
  flex items-center justify-center
49
56
  py-(--sp-space-2) text-(length:--sp-text-sm) text-(--sp-color-muted-fg)
@@ -54,20 +61,15 @@ module StimulusPlumbers
54
61
  py-(--sp-space-2) text-(length:--sp-text-sm) text-(--sp-color-muted-fg)
55
62
  ].freeze
56
63
 
57
- TIME = %w[flex gap-(--sp-space-2) overflow-hidden].freeze
58
-
59
- DATE_NAV = %w[flex items-center justify-between gap-(--sp-space-1) mb-(--sp-space-2)].freeze
60
-
61
- DATE_NAV_BTN = [
62
- *Control::BASE,
63
- "inline-flex items-center justify-center",
64
- "size-(--sp-calendar-day-size) rounded-(--sp-radius-md)",
65
- "text-(--sp-color-fg) hover:bg-(--sp-color-muted)",
66
- "focus-visible:ring-(--sp-focus-ring-color)"
67
- ].freeze
64
+ # ── Time picker ───────────────────────────────────────────────────────
65
+ TIME = %w[flex gap-(--sp-space-2) overflow-hidden].freeze
66
+ TIME_DRUM_UNIT = %w[flex-1 min-w-0].freeze
67
+ TIME_DRUM_PERIOD = %w[shrink-0].freeze
68
68
 
69
- CONTAINER = %w[relative].freeze
70
- POPOVER = %w[absolute top-full left-0 min-w-full].freeze
69
+ # ── Date navigation ───────────────────────────────────────────────────
70
+ DATE_NAV = %w[flex items-center justify-between gap-(--sp-space-1) mb-(--sp-space-2)].freeze
71
+ DATE_NAV_BTN = %w[].freeze
72
+ DATE_NAV_TITLE = %w[flex-1 text-center].freeze
71
73
 
72
74
  private
73
75
 
@@ -110,7 +112,7 @@ module StimulusPlumbers
110
112
  end
111
113
 
112
114
  def combobox_typeahead_loading_icon_classes
113
- { classes: klasses("size-(--sp-icon-size)", "animate-spin") }
115
+ { classes: klasses("size-(--sp-icon-size-md)", "animate-spin") }
114
116
  end
115
117
 
116
118
  def combobox_typeahead_empty_classes
@@ -121,6 +123,10 @@ module StimulusPlumbers
121
123
  { classes: klasses(*TIME) }
122
124
  end
123
125
 
126
+ def combobox_time_drum_classes(type: :unit)
127
+ { classes: klasses(*(type == :period ? TIME_DRUM_PERIOD : TIME_DRUM_UNIT)) }
128
+ end
129
+
124
130
  def combobox_date_navigation_classes
125
131
  { classes: klasses(*DATE_NAV) }
126
132
  end
@@ -128,6 +134,10 @@ module StimulusPlumbers
128
134
  def combobox_date_navigation_navigator_classes
129
135
  { classes: klasses(*DATE_NAV_BTN) }
130
136
  end
137
+
138
+ def combobox_date_navigation_title_classes
139
+ { classes: klasses(*DATE_NAV_TITLE) }
140
+ end
131
141
  end
132
142
  end
133
143
  end