stimulus_plumbers_tailwind 0.3.1

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 ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 9276ad8bfe52d19448c0e3571e8ab449d32a92157c88ee4711397919d1df25e8
4
+ data.tar.gz: 013d01a397e3d8efaba9fe5addf41d10d1bf5dfe98f4c89e551c0de69aa61f13
5
+ SHA512:
6
+ metadata.gz: d0c7e9fb5e48a6610dff539bc4a1e153faef1b6237bfe19593eb746f4b5c66520bd00931f2e6e3ea23c3214f13b5cd32055352a8d0ee982052a9eae570fc7da5
7
+ data.tar.gz: c71d3ccc142cbd8566fe77bf4b0e2bd7d002854525e59351739be5a6a122ea492619007f3c7a7afaba448d55de491c117a1f20f7227d7f90266d8b249b3f5d3f
data/CHANGELOG.md ADDED
@@ -0,0 +1,12 @@
1
+ # Changelog
2
+
3
+ All notable changes to this project will be documented in this file. See [conventional commits](https://www.conventionalcommits.org/) for commit guidelines.
4
+
5
+ ---
6
+ ## [0.3.1] - 2026-05-19
7
+
8
+ ### Features
9
+
10
+ - tailwind gem ([#74](https://github.com/ryancyq/stimulus-plumbers/issues/74)) - ([d9cbbdc](https://github.com/ryancyq/stimulus-plumbers/commit/d9cbbdce65d1d6f93773613a477ea082912af967)) - Ryan Chang
11
+
12
+ <!-- generated by git-cliff -->
data/README.md ADDED
@@ -0,0 +1,88 @@
1
+ # stimulus-plumbers-tailwind
2
+
3
+ [![Version][rubygems_badge]][rubygems]
4
+ [![CI][ci_badge]][ci]
5
+ [![Coverage][coverage_badge]][coverage]
6
+
7
+ Tailwind CSS v4 theme for [`stimulus_plumbers`](../stimulus-plumbers-rails). Extends the base theme with utility classes for all components.
8
+
9
+ ## Requirements
10
+
11
+ - Ruby >= 3.0
12
+ - `stimulus_plumbers` >= 0.2.9
13
+ - Tailwind CSS v4 in your build toolchain
14
+
15
+ ## Installation
16
+
17
+ ```ruby
18
+ # Gemfile
19
+ gem "stimulus_plumbers_tailwind"
20
+ ```
21
+
22
+ ```bash
23
+ bundle install
24
+ ```
25
+
26
+ Activate the theme in an initializer or `config/application.rb`:
27
+
28
+ ```ruby
29
+ StimulusPlumbers.configure do |config|
30
+ config.theme = :tailwind
31
+ end
32
+ ```
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:
35
+
36
+ ```css
37
+ @import "tailwindcss";
38
+ @source "/path/to/gems/stimulus_plumbers_tailwind-VERSION/lib/**/*.rb";
39
+ ```
40
+
41
+ Use `bundle show stimulus_plumbers_tailwind` to get the exact installed path.
42
+
43
+ ## Theming
44
+
45
+ `StimulusPlumbers::Themes::TailwindTheme` subclasses `StimulusPlumbers::Themes::Base` and provides CSS class resolution for all component families:
46
+
47
+ | Module | Components |
48
+ |--------|------------|
49
+ | `Tailwind::ActionList` | Action list, menu items |
50
+ | `Tailwind::Avatar` | Avatar |
51
+ | `Tailwind::Button` | Button |
52
+ | `Tailwind::Calendar` | Calendar grid, date picker |
53
+ | `Tailwind::Card` | Card |
54
+ | `Tailwind::Combobox` | Combobox (date, time, dropdown, autocomplete) |
55
+ | `Tailwind::Form` | Form fields, labels, errors |
56
+ | `Tailwind::Layout` | Layout primitives |
57
+
58
+ Custom themes can subclass `TailwindTheme` to override individual methods, or subclass `StimulusPlumbers::Themes::Base` directly.
59
+
60
+ ## Development
61
+
62
+ ```bash
63
+ bundle install
64
+ npm install
65
+
66
+ bundle exec rake test:unit # unit tests
67
+ npm run test:snapshots # visual snapshot tests (Playwright)
68
+ npm run test:snapshots:update # regenerate baseline screenshots
69
+ bundle exec rake rubocop # lint
70
+ bundle exec rake coverage # run tests with coverage + collate report
71
+ ```
72
+
73
+ The sandbox Rails app lives in `test/sandbox/`. Run it with:
74
+
75
+ ```bash
76
+ bundle exec puma test/sandbox/config.ru
77
+ ```
78
+
79
+ ## License
80
+
81
+ [MIT](https://opensource.org/licenses/MIT)
82
+
83
+ [rubygems_badge]: https://img.shields.io/gem/v/stimulus_plumbers_tailwind.svg
84
+ [rubygems]: https://rubygems.org/gems/stimulus_plumbers_tailwind
85
+ [ci_badge]: https://github.com/ryancyq/stimulus-plumbers/actions/workflows/ci-tailwind.yml/badge.svg
86
+ [ci]: https://github.com/ryancyq/stimulus-plumbers/actions/workflows/ci-tailwind.yml
87
+ [coverage_badge]: https://codecov.io/gh/ryancyq/stimulus-plumbers/graph/badge.svg?token=Z77H6M5GER&flag=tailwind
88
+ [coverage]: https://codecov.io/gh/ryancyq/stimulus-plumbers
@@ -0,0 +1,33 @@
1
+ # frozen_string_literal: true
2
+
3
+ module StimulusPlumbers
4
+ module Themes
5
+ module Tailwind
6
+ module ActionList
7
+ LIST_ITEM_ACTIVE = %w[bg-(--sp-color-primary)/10 text-(--sp-color-primary)].freeze
8
+ LIST_ITEM_BASE = %w[
9
+ flex items-center gap-(--sp-space-2) w-full
10
+ px-(--sp-space-2) py-(--sp-space-1)
11
+ rounded-(--sp-radius-sm) text-(--sp-text-sm)
12
+ cursor-pointer select-none outline-none
13
+ hover:bg-(--sp-color-muted) focus:bg-(--sp-color-muted) focus:text-(--sp-color-fg)
14
+ ].freeze
15
+
16
+ private
17
+
18
+ def action_list_classes
19
+ { classes: klasses("py-(--sp-space-1)") }
20
+ end
21
+
22
+ def action_list_item_classes(active: false)
23
+ {
24
+ classes: klasses(
25
+ *LIST_ITEM_BASE,
26
+ *(active ? LIST_ITEM_ACTIVE : [])
27
+ )
28
+ }
29
+ end
30
+ end
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,52 @@
1
+ # frozen_string_literal: true
2
+
3
+ module StimulusPlumbers
4
+ module Themes
5
+ module Tailwind
6
+ module Avatar
7
+ COLORS = {
8
+ amber: "text-white bg-amber-600",
9
+ lime: "text-white bg-lime-600",
10
+ sky: "text-white bg-sky-600",
11
+ cyan: "text-white bg-cyan-600",
12
+ teal: "text-white bg-teal-600",
13
+ emerald: "text-white bg-emerald-600",
14
+ indigo: "text-white bg-indigo-600",
15
+ fuchsia: "text-white bg-fuchsia-600",
16
+ rose: "text-white bg-rose-600",
17
+ pink: "text-white bg-pink-600",
18
+ violet: "text-white bg-violet-600",
19
+ blue: "text-white bg-blue-600"
20
+ }.freeze
21
+
22
+ SIZES = {
23
+ sm: "size-(--sp-icon-size)",
24
+ md: "size-(--sp-avatar-size)",
25
+ lg: "size-12"
26
+ }.freeze
27
+
28
+ BASE = %w[rounded-(--sp-radius-full) overflow-hidden inline-flex items-center justify-center].freeze
29
+
30
+ def avatar_colors
31
+ COLORS
32
+ end
33
+
34
+ def avatar_color_range
35
+ COLORS.values
36
+ end
37
+
38
+ private
39
+
40
+ def avatar_classes(size: :md, color: nil)
41
+ {
42
+ classes: klasses(
43
+ SIZES.fetch(size, SIZES[:md]),
44
+ COLORS.fetch(color, nil),
45
+ *BASE
46
+ )
47
+ }
48
+ end
49
+ end
50
+ end
51
+ end
52
+ end
@@ -0,0 +1,89 @@
1
+ # frozen_string_literal: true
2
+
3
+ module StimulusPlumbers
4
+ module Themes
5
+ module Tailwind
6
+ module Button
7
+ VARIANTS = {
8
+ primary: %w[
9
+ bg-(--sp-color-primary)
10
+ text-(--sp-color-primary-fg)
11
+ hover:bg-(--sp-color-primary)/90
12
+ focus-visible:ring-(--sp-focus-ring-color)
13
+ ].freeze,
14
+ secondary: %w[
15
+ bg-(--sp-color-muted)
16
+ text-(--sp-color-fg)
17
+ hover:bg-(--sp-color-border)
18
+ ].freeze,
19
+ outline: %w[
20
+ border border-(--sp-color-border)
21
+ bg-transparent
22
+ text-(--sp-color-fg)
23
+ hover:bg-(--sp-color-muted)
24
+ ].freeze,
25
+ destructive: %w[
26
+ bg-(--sp-color-destructive)
27
+ text-(--sp-color-destructive-fg)
28
+ hover:bg-(--sp-color-destructive)/90
29
+ ].freeze,
30
+ ghost: %w[hover:bg-(--sp-color-muted) text-(--sp-color-fg)].freeze,
31
+ link: %w[text-(--sp-color-primary) underline-offset-4 hover:underline].freeze
32
+ }.freeze
33
+
34
+ SIZES = {
35
+ sm: %w[h-8 px-(--sp-space-3) text-(--sp-text-sm)].freeze,
36
+ md: %w[h-9 px-(--sp-space-4) text-(--sp-text-base)].freeze,
37
+ lg: %w[h-11 px-(--sp-space-6) text-(--sp-text-lg)].freeze
38
+ }.freeze
39
+
40
+ FLEX_ALIGN = {
41
+ row: {
42
+ left: "justify-start",
43
+ center: %w[justify-center items-center].freeze,
44
+ right: "justify-end",
45
+ top: "items-start",
46
+ bottom: "items-end"
47
+ }.freeze,
48
+ col: {
49
+ top: "justify-start",
50
+ center: %w[justify-center items-center].freeze,
51
+ bottom: "justify-end",
52
+ left: "items-start",
53
+ right: "items-end"
54
+ }.freeze
55
+ }.freeze
56
+
57
+ BASE = %w[
58
+ inline-flex items-center justify-center gap-2 font-medium
59
+ rounded-(--sp-radius-md) transition-colors
60
+ focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-offset-2
61
+ disabled:pointer-events-none disabled:opacity-50
62
+ ].freeze
63
+
64
+ GROUP_BASE = %w[flex gap-(--sp-space-2)].freeze
65
+
66
+ private
67
+
68
+ def button_classes(variant: :primary, size: :md)
69
+ {
70
+ classes: klasses(
71
+ *BASE,
72
+ *VARIANTS.fetch(variant, []),
73
+ *SIZES.fetch(size, [])
74
+ )
75
+ }
76
+ end
77
+
78
+ def button_group_classes(alignment: :left, direction: :row)
79
+ {
80
+ classes: klasses(
81
+ *GROUP_BASE,
82
+ *Array(FLEX_ALIGN.dig(direction, alignment))
83
+ )
84
+ }
85
+ end
86
+ end
87
+ end
88
+ end
89
+ end
@@ -0,0 +1,84 @@
1
+ # frozen_string_literal: true
2
+
3
+ module StimulusPlumbers
4
+ module Themes
5
+ module Tailwind
6
+ module Calendar
7
+ GRID = %w[w-full].freeze
8
+
9
+ DAYS_OF_WEEK = %w[
10
+ grid grid-cols-7 text-center text-(--sp-text-xs)
11
+ font-medium text-(--sp-color-muted-fg) mb-1
12
+ ].freeze
13
+
14
+ DAYS_OF_MONTH = %w[grid grid-cols-7 justify-items-center].freeze
15
+
16
+ DAY = %w[
17
+ size-(--sp-calendar-day-size) rounded-(--sp-radius-md)
18
+ flex items-center justify-center text-(--sp-text-sm)
19
+ hover:bg-(--sp-color-muted) cursor-pointer
20
+ ].freeze
21
+
22
+ DAY_SELECTED = %w[
23
+ bg-(--sp-color-primary)
24
+ text-(--sp-color-primary-fg)
25
+ hover:bg-(--sp-color-primary)/90
26
+ ].freeze
27
+
28
+ NAV = %w[flex items-center justify-between gap-1 mb-2].freeze
29
+
30
+ NAV_BTN = %w[
31
+ inline-flex items-center justify-center
32
+ size-(--sp-calendar-day-size) rounded-(--sp-radius-md)
33
+ text-(--sp-color-fg) hover:bg-(--sp-color-muted)
34
+ focus-visible:outline-none focus-visible:ring-2
35
+ focus-visible:ring-(--sp-focus-ring-color)
36
+ disabled:pointer-events-none disabled:opacity-50
37
+ ].freeze
38
+
39
+ NAV_ICON = %w[size-4 stroke-current].freeze
40
+
41
+ private
42
+
43
+ def calendar_classes
44
+ { classes: klasses(*GRID) }
45
+ end
46
+
47
+ def calendar_days_of_week_classes
48
+ { classes: klasses(*DAYS_OF_WEEK) }
49
+ end
50
+
51
+ def calendar_week_classes
52
+ { classes: "contents" }
53
+ end
54
+
55
+ def calendar_days_of_month_classes
56
+ { classes: klasses(*DAYS_OF_MONTH) }
57
+ end
58
+
59
+ def calendar_day_classes(today: false, selected: false, outside: false)
60
+ {
61
+ classes: klasses(
62
+ *DAY,
63
+ *(today ? ["font-bold"] : []),
64
+ *(selected ? DAY_SELECTED : []),
65
+ *(outside ? %w[text-(--sp-color-muted-fg) opacity-50] : [])
66
+ )
67
+ }
68
+ end
69
+
70
+ def calendar_navigation_classes
71
+ { classes: klasses(*NAV) }
72
+ end
73
+
74
+ def calendar_navigation_navigator_classes
75
+ { classes: klasses(*NAV_BTN) }
76
+ end
77
+
78
+ def calendar_navigation_navigator_icon_classes
79
+ { classes: klasses(*NAV_ICON) }
80
+ end
81
+ end
82
+ end
83
+ end
84
+ end
@@ -0,0 +1,24 @@
1
+ # frozen_string_literal: true
2
+
3
+ module StimulusPlumbers
4
+ module Themes
5
+ module Tailwind
6
+ module Card
7
+ BASE = %w[
8
+ rounded-(--sp-radius-lg) border border-(--sp-color-border)
9
+ bg-(--sp-color-bg) shadow-(--sp-shadow-sm)
10
+ ].freeze
11
+
12
+ private
13
+
14
+ def card_classes
15
+ { classes: klasses(*BASE) }
16
+ end
17
+
18
+ def card_section_classes
19
+ { classes: klasses("p-(--sp-space-6)") }
20
+ end
21
+ end
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,86 @@
1
+ # frozen_string_literal: true
2
+
3
+ module StimulusPlumbers
4
+ module Themes
5
+ module Tailwind
6
+ module Combobox
7
+ TRIGGER = %w[
8
+ w-full rounded-(--sp-radius-md) border border-(--sp-color-muted-fg)
9
+ px-(--sp-space-3) py-(--sp-space-2)
10
+ text-(--sp-text-sm) text-(--sp-color-fg) bg-(--sp-color-bg)
11
+ focus:outline-none focus:ring-2 focus:ring-(--sp-focus-ring-color)
12
+ ].freeze
13
+
14
+ LISTBOX = %w[
15
+ py-(--sp-space-1) overflow-y-auto max-h-60
16
+ ].freeze
17
+
18
+ OPTION_BASE = %w[
19
+ flex items-center gap-(--sp-space-2) w-full
20
+ px-(--sp-space-2) py-(--sp-space-1)
21
+ rounded-(--sp-radius-sm) text-(--sp-text-sm)
22
+ cursor-pointer select-none outline-none
23
+ hover:bg-(--sp-color-muted) focus:bg-(--sp-color-muted)
24
+ ].freeze
25
+
26
+ OPTION_SELECTED = %w[
27
+ bg-(--sp-color-primary)/10 text-(--sp-color-primary)
28
+ ].freeze
29
+
30
+ OPTION_DISABLED = %w[
31
+ opacity-50 cursor-not-allowed pointer-events-none
32
+ ].freeze
33
+
34
+ OPTION_GROUP = %w[py-(--sp-space-1)].freeze
35
+
36
+ AUTOCOMPLETE_LOADING = %w[
37
+ flex items-center justify-center
38
+ py-(--sp-space-2) text-(--sp-text-sm) text-(--sp-color-muted-fg)
39
+ ].freeze
40
+
41
+ AUTOCOMPLETE_EMPTY = %w[
42
+ flex items-center justify-center
43
+ py-(--sp-space-2) text-(--sp-text-sm) text-(--sp-color-muted-fg)
44
+ ].freeze
45
+
46
+ TIME = %w[flex gap-(--sp-space-2) overflow-hidden].freeze
47
+
48
+ private
49
+
50
+ def combobox_trigger_classes
51
+ { classes: klasses(*TRIGGER) }
52
+ end
53
+
54
+ def combobox_listbox_classes
55
+ { classes: klasses(*LISTBOX) }
56
+ end
57
+
58
+ def combobox_option_classes(selected: false, disabled: false)
59
+ {
60
+ classes: klasses(
61
+ *OPTION_BASE,
62
+ *(selected ? OPTION_SELECTED : []),
63
+ *(disabled ? OPTION_DISABLED : [])
64
+ )
65
+ }
66
+ end
67
+
68
+ def combobox_option_group_classes
69
+ { classes: klasses(*OPTION_GROUP) }
70
+ end
71
+
72
+ def combobox_autocomplete_loading_classes
73
+ { classes: klasses(*AUTOCOMPLETE_LOADING) }
74
+ end
75
+
76
+ def combobox_autocomplete_empty_classes
77
+ { classes: klasses(*AUTOCOMPLETE_EMPTY) }
78
+ end
79
+
80
+ def combobox_time_classes
81
+ { classes: klasses(*TIME) }
82
+ end
83
+ end
84
+ end
85
+ end
86
+ end
@@ -0,0 +1,116 @@
1
+ # frozen_string_literal: true
2
+
3
+ module StimulusPlumbers
4
+ module Themes
5
+ module Tailwind
6
+ module Form
7
+ INPUT_BASE = %w[
8
+ w-full rounded-md border px-3 py-2 text-sm text-gray-900
9
+ bg-white focus:outline-none focus:ring-2 focus:ring-offset-0
10
+ ].freeze
11
+ INPUT_ERROR = %w[border-red-700 focus:ring-red-700].freeze
12
+ INPUT_DEFAULT = %w[border-gray-500 focus:ring-blue-700].freeze
13
+
14
+ GROUP_BASE = %w[flex gap-1 mb-3].freeze
15
+ GROUP_INLINE = %w[flex-row items-center].freeze
16
+
17
+ LABEL = %w[text-sm font-medium text-gray-900].freeze
18
+ REQUIRED_MARK = %w[text-red-700 ml-0.5].freeze
19
+ DETAILS = %w[text-xs text-gray-600].freeze
20
+ ERROR_TEXT = %w[text-xs text-red-700].freeze
21
+ CHECKBOX = %w[size-4 rounded border-gray-500 text-blue-700].freeze
22
+ RADIO = %w[size-4 border-gray-500 text-blue-700].freeze
23
+
24
+ INPUT_GROUP_BASE = %w[flex items-center overflow-hidden rounded-md border].freeze
25
+ INPUT_GROUP_BORDER = { error: "border-red-700", default: "border-gray-500" }.freeze
26
+
27
+ BUTTON_REVEAL = %w[
28
+ self-stretch border-0 bg-transparent px-3 cursor-pointer text-gray-600 hover:text-gray-900 text-sm
29
+ ].freeze
30
+ BUTTON_CLEAR = %w[
31
+ self-stretch border-0 bg-transparent px-2 cursor-pointer text-gray-500 hover:text-gray-900 text-sm
32
+ ].freeze
33
+ SUBMIT_LINK = %w[cursor-pointer text-sm font-medium text-gray-900 hover:underline].freeze
34
+
35
+ private
36
+
37
+ def form_group_classes(layout: :stacked, **_rest)
38
+ { classes: klasses(*GROUP_BASE, layout == :inline ? GROUP_INLINE : "flex-col") }
39
+ end
40
+
41
+ def form_label_classes(hidden: false, **)
42
+ { classes: klasses(*LABEL, hidden ? "sr-only" : nil) }
43
+ end
44
+
45
+ def form_required_mark_classes
46
+ { classes: klasses(*REQUIRED_MARK) }
47
+ end
48
+
49
+ def form_details_classes
50
+ { classes: klasses(*DETAILS) }
51
+ end
52
+
53
+ def form_error_classes
54
+ { classes: klasses(*ERROR_TEXT) }
55
+ end
56
+
57
+ def form_input_classes(error: false)
58
+ { classes: klasses(*INPUT_BASE, *(error ? INPUT_ERROR : INPUT_DEFAULT)) }
59
+ end
60
+
61
+ def form_textarea_classes(error: false)
62
+ form_input_classes(error: error)
63
+ end
64
+
65
+ def form_file_classes(error: false)
66
+ form_input_classes(error: error)
67
+ end
68
+
69
+ def form_select_classes(error: false)
70
+ form_input_classes(error: error)
71
+ end
72
+
73
+ def form_checkbox_classes(**)
74
+ { classes: klasses(*CHECKBOX) }
75
+ end
76
+
77
+ def form_radio_classes(**)
78
+ { classes: klasses(*RADIO) }
79
+ end
80
+
81
+ def form_input_group_classes(error: false)
82
+ { classes: klasses(*INPUT_GROUP_BASE, INPUT_GROUP_BORDER[error ? :error : :default]) }
83
+ end
84
+
85
+ def form_combobox_classes(error: false)
86
+ form_input_classes(error: error)
87
+ end
88
+
89
+ def form_input_reveal_classes(**)
90
+ { classes: "" }
91
+ end
92
+
93
+ def form_input_search_classes
94
+ { classes: "" }
95
+ end
96
+
97
+ def form_button_reveal_classes
98
+ { classes: klasses(*BUTTON_REVEAL) }
99
+ end
100
+
101
+ def form_button_clear_classes
102
+ { classes: klasses(*BUTTON_CLEAR) }
103
+ end
104
+
105
+ def form_submit_classes(variant: :default)
106
+ case variant
107
+ when :button
108
+ { classes: klasses(*Button::BASE, *Button::VARIANTS[:primary], *Button::SIZES[:md]) }
109
+ else
110
+ { classes: klasses(*SUBMIT_LINK) }
111
+ end
112
+ end
113
+ end
114
+ end
115
+ end
116
+ end
@@ -0,0 +1,24 @@
1
+ # frozen_string_literal: true
2
+
3
+ module StimulusPlumbers
4
+ module Themes
5
+ module Tailwind
6
+ module Icon
7
+ ICONS = {
8
+ "arrow-left" => { d: "M10.5 19.5 3 12m0 0 7.5-7.5M3 12h18" },
9
+ "arrow-right" => { d: "M13.5 4.5 21 12m0 0-7.5 7.5M21 12H3" }
10
+ }.freeze
11
+
12
+ def icons
13
+ ICONS
14
+ end
15
+
16
+ private
17
+
18
+ def icon_classes
19
+ { classes: "" }
20
+ end
21
+ end
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,25 @@
1
+ # frozen_string_literal: true
2
+
3
+ module StimulusPlumbers
4
+ module Themes
5
+ module Tailwind
6
+ module Layout
7
+ DIVIDER = %w[border-t border-(--sp-color-border) my-(--sp-space-1)].freeze
8
+ POPOVER = %w[
9
+ rounded-(--sp-radius-lg) border border-(--sp-color-border)
10
+ bg-(--sp-color-bg) shadow-(--sp-shadow-md) z-(--sp-z-popover)
11
+ ].freeze
12
+
13
+ private
14
+
15
+ def divider_classes
16
+ { classes: klasses(*DIVIDER) }
17
+ end
18
+
19
+ def popover_classes
20
+ { classes: klasses(*POPOVER) }
21
+ end
22
+ end
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,33 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "tailwind/action_list"
4
+ require_relative "tailwind/avatar"
5
+ require_relative "tailwind/button"
6
+ require_relative "tailwind/calendar"
7
+ require_relative "tailwind/card"
8
+ require_relative "tailwind/combobox"
9
+ require_relative "tailwind/form"
10
+ require_relative "tailwind/icon"
11
+ require_relative "tailwind/layout"
12
+
13
+ module StimulusPlumbers
14
+ module Themes
15
+ class TailwindTheme < Base
16
+ include Tailwind::ActionList
17
+ include Tailwind::Combobox
18
+ include Tailwind::Avatar
19
+ include Tailwind::Button
20
+ include Tailwind::Calendar
21
+ include Tailwind::Card
22
+ include Tailwind::Form
23
+ include Tailwind::Icon
24
+ include Tailwind::Layout
25
+
26
+ private
27
+
28
+ def klasses(*classes)
29
+ classes.flatten.reject(&:blank?).join(" ")
30
+ end
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,11 @@
1
+ # frozen_string_literal: true
2
+
3
+ module StimulusPlumbersTailwind
4
+ class Engine < ::Rails::Engine
5
+ initializer "stimulus_plumbers_tailwind.register_theme" do
6
+ StimulusPlumbers.configure do |c|
7
+ c.theme.register(:tailwind, StimulusPlumbers::Themes::TailwindTheme)
8
+ end
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ module StimulusPlumbersTailwind
4
+ VERSION = "0.3.1"
5
+ end
@@ -0,0 +1,14 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "stimulus_plumbers"
4
+
5
+ require_relative "stimulus_plumbers_tailwind/version"
6
+ require_relative "stimulus_plumbers/themes/tailwind_theme"
7
+
8
+ if defined?(Rails::Engine)
9
+ require_relative "stimulus_plumbers_tailwind/engine"
10
+ else
11
+ StimulusPlumbers.configure do |c|
12
+ c.theme.register(:tailwind, StimulusPlumbers::Themes::TailwindTheme)
13
+ end
14
+ end
metadata ADDED
@@ -0,0 +1,74 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: stimulus_plumbers_tailwind
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.3.1
5
+ platform: ruby
6
+ authors:
7
+ - Ryan Chang
8
+ bindir: bin
9
+ cert_chain: []
10
+ date: 1980-01-02 00:00:00.000000000 Z
11
+ dependencies:
12
+ - !ruby/object:Gem::Dependency
13
+ name: stimulus_plumbers
14
+ requirement: !ruby/object:Gem::Requirement
15
+ requirements:
16
+ - - ">="
17
+ - !ruby/object:Gem::Version
18
+ version: 0.2.9
19
+ type: :runtime
20
+ prerelease: false
21
+ version_requirements: !ruby/object:Gem::Requirement
22
+ requirements:
23
+ - - ">="
24
+ - !ruby/object:Gem::Version
25
+ version: 0.2.9
26
+ description: Extends stimulus_plumbers with a Tailwind CSS v4 theme
27
+ email:
28
+ - ryancyq@gmail.com
29
+ executables: []
30
+ extensions: []
31
+ extra_rdoc_files: []
32
+ files:
33
+ - CHANGELOG.md
34
+ - README.md
35
+ - lib/stimulus_plumbers/themes/tailwind/action_list.rb
36
+ - lib/stimulus_plumbers/themes/tailwind/avatar.rb
37
+ - lib/stimulus_plumbers/themes/tailwind/button.rb
38
+ - lib/stimulus_plumbers/themes/tailwind/calendar.rb
39
+ - lib/stimulus_plumbers/themes/tailwind/card.rb
40
+ - lib/stimulus_plumbers/themes/tailwind/combobox.rb
41
+ - lib/stimulus_plumbers/themes/tailwind/form.rb
42
+ - lib/stimulus_plumbers/themes/tailwind/icon.rb
43
+ - lib/stimulus_plumbers/themes/tailwind/layout.rb
44
+ - lib/stimulus_plumbers/themes/tailwind_theme.rb
45
+ - lib/stimulus_plumbers_tailwind.rb
46
+ - lib/stimulus_plumbers_tailwind/engine.rb
47
+ - lib/stimulus_plumbers_tailwind/version.rb
48
+ homepage: https://github.com/ryancyq/stimulus-plumbers
49
+ licenses:
50
+ - MIT
51
+ metadata:
52
+ rubygems_mfa_required: 'true'
53
+ allowed_push_host: https://rubygems.org
54
+ changelog_uri: https://github.com/ryancyq/stimulus-plumbers/blob/main/CHANGELOG.md
55
+ homepage_uri: https://github.com/ryancyq/stimulus-plumbers
56
+ source_code_uri: https://github.com/ryancyq/stimulus-plumbers/tree/main/stimulus-plumbers-tailwind
57
+ rdoc_options: []
58
+ require_paths:
59
+ - lib
60
+ required_ruby_version: !ruby/object:Gem::Requirement
61
+ requirements:
62
+ - - ">="
63
+ - !ruby/object:Gem::Version
64
+ version: '3.0'
65
+ required_rubygems_version: !ruby/object:Gem::Requirement
66
+ requirements:
67
+ - - ">="
68
+ - !ruby/object:Gem::Version
69
+ version: 3.2.0
70
+ requirements: []
71
+ rubygems_version: 3.6.9
72
+ specification_version: 4
73
+ summary: Tailwind CSS theme for stimulus_plumbers
74
+ test_files: []