stimulus_plumbers_tailwind 0.3.3 → 0.4.2

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: d9538346c119b8c1b5ad69324b708e083393e2ff6c46bd777ff3b4f22833426f
4
- data.tar.gz: ba2636473fbf2f74b3286a09efb10a4f68d5d431236ff70a8f1bd12654feac37
3
+ metadata.gz: d7821a54d820ecd2c76e2ce5afd0bcd00ab4fb2f78f3e4246a256a378b3bd631
4
+ data.tar.gz: f67b19c723fe3ba0e22c5f7e94698575bf17e905d6ec4db9305b919d6ae4a471
5
5
  SHA512:
6
- metadata.gz: 70224de388f2e9236cdb877212d5aa81d2a386efc98060bfc0bad2c78be686768a6d54eb5647c9a2cb06cc5218bcaa700161dd43b53356e85b99f1d76c3b30d8
7
- data.tar.gz: 72d13eb1f2f751a7240a8af5d4faa47757f75157ab6806a0dd12245fe53f0f5f907d51d8b10508db0a592d7bb84772214c6483655c1e68a2529ead3b4b135f20
6
+ metadata.gz: 959b1d2a0f740c5630d85cc824da0148e7c172e9052b6359f4c873ee5c24ac23afdddf6bc5d4cd76602373f5c3f7d90cd0649fe13185b5eeb9b802deed618a6e
7
+ data.tar.gz: 4a0dd9d2040676acd2671eda6b2840ebb320f6704ce93ed23dcdcbb008ab37bc9abdd30e132bb224d9f0a97aa069941bdd4ee76b650eeeb71d97b7b12fe14f25
data/CHANGELOG.md CHANGED
@@ -2,6 +2,74 @@
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.2](https://github.com/ryancyq/stimulus-plumbers/compare/stimulus-plumbers-tailwind/v0.4.0..stimulus-plumbers-tailwind/v0.4.2) - 2026-06-30
7
+
8
+ ### Bug Fixes
9
+
10
+ - form submit button style ([#127](https://github.com/ryancyq/stimulus-plumbers/issues/127)) - ([2bbc73f](https://github.com/ryancyq/stimulus-plumbers/commit/2bbc73f15b7ffa2d9d8f87991adead33fab8156e)) - Ryan Chang
11
+ - various component styles ([#128](https://github.com/ryancyq/stimulus-plumbers/issues/128)) - ([011cc69](https://github.com/ryancyq/stimulus-plumbers/commit/011cc69bb6df3770949564521cdf949493d028cc)) - Ryan Chang
12
+ - 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
13
+ - combobox time ([#130](https://github.com/ryancyq/stimulus-plumbers/issues/130)) - ([ff5d968](https://github.com/ryancyq/stimulus-plumbers/commit/ff5d968da34fc723b0112a791bd95ef43f2b1640)) - Ryan Chang
14
+ - 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
15
+ - 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
16
+ - accessibility + plumber helpers ([#136](https://github.com/ryancyq/stimulus-plumbers/issues/136)) - ([e84053d](https://github.com/ryancyq/stimulus-plumbers/commit/e84053d43db4726c3704d459a0464f70529fff8b)) - Ryan Chang
17
+ - 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
18
+
19
+ ### Dependencies
20
+
21
+ - **(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]
22
+ - **(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]
23
+
24
+ ### Documentation
25
+
26
+ - 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
27
+ - update component documentation - ([89ecb78](https://github.com/ryancyq/stimulus-plumbers/commit/89ecb786d88eed66ab925921ac182aa84560207d)) - Ryan Chang
28
+
29
+ ### Features
30
+
31
+ - calendar redesign ([#133](https://github.com/ryancyq/stimulus-plumbers/issues/133)) - ([e19df95](https://github.com/ryancyq/stimulus-plumbers/commit/e19df95f3814b3d947142722ff0295f1bdcef6b3)) - Ryan Chang
32
+
33
+ ### Tests
34
+
35
+ - 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
36
+ - update collection radio locator - ([f0fa9e8](https://github.com/ryancyq/stimulus-plumbers/commit/f0fa9e85bc0b835b3adc46f5dc406a8bdedbeefe)) - Ryan Chang
37
+
38
+ ---
39
+ ## [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
40
+
41
+ ### Bug Fixes
42
+
43
+ - separate form field/choice rendering ([#92](https://github.com/ryancyq/stimulus-plumbers/issues/92)) - ([beedf5f](https://github.com/ryancyq/stimulus-plumbers/commit/beedf5f25849fd8e0411db69733bdb7afda99d9c)) - Ryan Chang
44
+ - redesign combobox + popover integration ([#93](https://github.com/ryancyq/stimulus-plumbers/issues/93)) - ([acffee6](https://github.com/ryancyq/stimulus-plumbers/commit/acffee6e8661daa9245223eb4c95df9d066ff452)) - Ryan Chang
45
+ - avatar image theme ([#102](https://github.com/ryancyq/stimulus-plumbers/issues/102)) - ([8135d9b](https://github.com/ryancyq/stimulus-plumbers/commit/8135d9bf03df72365b66a22d4c4bfad356c3007f)) - Ryan Chang
46
+ - button link with external url will have icon render by default ([#103](https://github.com/ryancyq/stimulus-plumbers/issues/103)) - ([0429cba](https://github.com/ryancyq/stimulus-plumbers/commit/0429cbab170d5a4a7a5009fe0f70023917521725)) - Ryan Chang
47
+ - action list / popover builder ([#105](https://github.com/ryancyq/stimulus-plumbers/issues/105)) - ([fc27045](https://github.com/ryancyq/stimulus-plumbers/commit/fc2704527cec4a8e3f5ea5119de33026c936defb)) - Ryan Chang
48
+ - button group builder ([#107](https://github.com/ryancyq/stimulus-plumbers/issues/107)) - ([c649df2](https://github.com/ryancyq/stimulus-plumbers/commit/c649df22162758958d4bfcd5a13f56c9bbb61eb6)) - Ryan Chang
49
+ - floating label for form inputs ([#109](https://github.com/ryancyq/stimulus-plumbers/issues/109)) - ([16c1c9b](https://github.com/ryancyq/stimulus-plumbers/commit/16c1c9ba2601dbbd9819be2272836a0f56b0b404)) - Ryan Chang
50
+ - calendar + combobox date ([#110](https://github.com/ryancyq/stimulus-plumbers/issues/110)) - ([d47065f](https://github.com/ryancyq/stimulus-plumbers/commit/d47065fc888bd81c2e72066dc98d061ff8a6e5a7)) - Ryan Chang
51
+ - action list with builder ([#111](https://github.com/ryancyq/stimulus-plumbers/issues/111)) - ([8ba6c3f](https://github.com/ryancyq/stimulus-plumbers/commit/8ba6c3f4a4c51d8e95c57fdde5e7ba499cc17e86)) - Ryan Chang
52
+ - icon helper + update doc ([#113](https://github.com/ryancyq/stimulus-plumbers/issues/113)) - ([301adf4](https://github.com/ryancyq/stimulus-plumbers/commit/301adf406102d2d98b8cbd65cb2e3f4f921b5a2e)) - Ryan Chang
53
+
54
+ ### Features
55
+
56
+ - form floating label ([#96](https://github.com/ryancyq/stimulus-plumbers/issues/96)) - ([13e9854](https://github.com/ryancyq/stimulus-plumbers/commit/13e985424cd2460820f5ae0e7d5c6debad6392e4)) - Ryan Chang
57
+ - button variant type ([#97](https://github.com/ryancyq/stimulus-plumbers/issues/97)) - ([c680077](https://github.com/ryancyq/stimulus-plumbers/commit/c680077f14df2aad943c84ed2559d87bcf41e12b)) - Ryan Chang
58
+ - calendar with days/months/years views ([#99](https://github.com/ryancyq/stimulus-plumbers/issues/99)) - ([fa530c8](https://github.com/ryancyq/stimulus-plumbers/commit/fa530c8eea38351e08cc27ad66aa6733fdb44f46)) - Ryan Chang
59
+ - button fab outline ([#104](https://github.com/ryancyq/stimulus-plumbers/issues/104)) - ([ba877d8](https://github.com/ryancyq/stimulus-plumbers/commit/ba877d8312fcb8362ccd287173af12651e6b7627)) - Ryan Chang
60
+
61
+ ### Style
62
+
63
+ - update component styling ([#89](https://github.com/ryancyq/stimulus-plumbers/issues/89)) - ([be240aa](https://github.com/ryancyq/stimulus-plumbers/commit/be240aa2a8e9a92b66c95086a8c5d0cfff067da4)) - Ryan Chang
64
+ - tailwind choice checkbox/radio ([#95](https://github.com/ryancyq/stimulus-plumbers/issues/95)) - ([1c56b75](https://github.com/ryancyq/stimulus-plumbers/commit/1c56b753596f2d28b4d2320004ae32046e474f8a)) - Ryan Chang
65
+ - fix card style across button/link/checkbox/radio ([#108](https://github.com/ryancyq/stimulus-plumbers/issues/108)) - ([6c6f2cc](https://github.com/ryancyq/stimulus-plumbers/commit/6c6f2ccfaca8bffdf186062ad73c38ebee5bdd21)) - Ryan Chang
66
+
67
+ ### Tests
68
+
69
+ - add snapshots coverage ([#91](https://github.com/ryancyq/stimulus-plumbers/issues/91)) - ([bbd6022](https://github.com/ryancyq/stimulus-plumbers/commit/bbd6022ad37af9a1553971b6a4a928786eb7c421)) - Ryan Chang
70
+ - address unit/a11y test gaps ([#101](https://github.com/ryancyq/stimulus-plumbers/issues/101)) - ([68f30e1](https://github.com/ryancyq/stimulus-plumbers/commit/68f30e1ddd1b11a6ab315beb40eb55a4a2946001)) - Ryan Chang
71
+ - update sandbox view and snapshot spec ([#120](https://github.com/ryancyq/stimulus-plumbers/issues/120)) - ([d331248](https://github.com/ryancyq/stimulus-plumbers/commit/d331248a082bbc598cad35d38ab16dbde3563c19)) - Ryan Chang
72
+
5
73
  ---
6
74
  ## [0.3.3](https://github.com/ryancyq/stimulus-plumbers/compare/stimulus-plumbers-tailwind/v0.3.2..stimulus-plumbers-tailwind/v0.3.3) - 2026-05-26
7
75
 
data/README.md CHANGED
@@ -27,7 +27,7 @@ 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
 
@@ -46,7 +46,6 @@ Use `bundle show stimulus_plumbers_tailwind` to get the exact installed path.
46
46
 
47
47
  | Module | Components |
48
48
  |--------|------------|
49
- | `Tailwind::ActionList` | Action list, menu items |
50
49
  | `Tailwind::Avatar` | Avatar |
51
50
  | `Tailwind::Button` | Button |
52
51
  | `Tailwind::Calendar` | Calendar grid, date picker |
@@ -55,6 +54,9 @@ Use `bundle show stimulus_plumbers_tailwind` to get the exact installed path.
55
54
  | `Tailwind::Form` | Form fields, labels, errors |
56
55
  | `Tailwind::Icon` | Icon (SVG rendering, icon registry) |
57
56
  | `Tailwind::Layout` | Layout primitives |
57
+ | `Tailwind::Link` | Link |
58
+ | `Tailwind::List` | List |
59
+ | `Tailwind::Timeline` | Timeline |
58
60
 
59
61
  Custom themes can subclass `TailwindTheme` to override individual methods, or subclass `StimulusPlumbers::Themes::Base` directly.
60
62
 
@@ -85,8 +87,8 @@ bundle install
85
87
  npm install
86
88
 
87
89
  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
90
+ node --run test:snapshots # visual snapshot tests (Playwright)
91
+ node --run test:snapshots:update # regenerate baseline screenshots
90
92
  bundle exec rake rubocop # lint
91
93
  bundle exec rake coverage # run tests with coverage + collate report
92
94
  ```
@@ -4,7 +4,19 @@ module StimulusPlumbers
4
4
  module Themes
5
5
  module Tailwind
6
6
  module Avatar
7
- COLORS = {
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
+
19
+ VARIANTS = {
8
20
  amber: "text-white bg-amber-600",
9
21
  lime: "text-white bg-lime-600",
10
22
  sky: "text-white bg-sky-600",
@@ -19,33 +31,29 @@ 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[rounded-(--sp-radius-full) overflow-hidden inline-flex items-center justify-center].freeze
29
-
30
- def avatar_colors
31
- COLORS
34
+ def avatar_variants
35
+ VARIANTS
32
36
  end
33
37
 
34
- def avatar_color_range
35
- COLORS.values
38
+ def avatar_variant_range
39
+ VARIANTS.values
36
40
  end
37
41
 
38
42
  private
39
43
 
40
- def avatar_classes(size: :md, color: nil)
44
+ def avatar_classes(size: :md, variant: nil)
41
45
  {
42
46
  classes: klasses(
43
47
  SIZES.fetch(size, SIZES[:md]),
44
- COLORS.fetch(color, nil),
48
+ VARIANTS.fetch(variant, nil),
45
49
  *BASE
46
50
  )
47
51
  }
48
52
  end
53
+
54
+ def avatar_image_classes
55
+ { classes: "w-full h-full object-cover" }
56
+ end
49
57
  end
50
58
  end
51
59
  end
@@ -0,0 +1,36 @@
1
+ # frozen_string_literal: true
2
+
3
+ module StimulusPlumbers
4
+ module Themes
5
+ module Tailwind
6
+ module Button
7
+ module Group
8
+ LAYOUTS = {
9
+ inline: %w[
10
+ inline-flex rounded-(--sp-radius-md) shadow-(--sp-shadow-xs)
11
+ [&>*:not(:first-child)]:-ml-px
12
+ [&>*]:rounded-none
13
+ [&>*:first-child]:rounded-s-(--sp-radius-md)
14
+ [&>*:last-child]:rounded-e-(--sp-radius-md)
15
+ ].freeze,
16
+ stacked: %w[
17
+ flex flex-col rounded-(--sp-radius-md) shadow-(--sp-shadow-xs)
18
+ [&>*:not(:first-child)]:-mt-px
19
+ [&>*]:rounded-none
20
+ [&>*:first-child]:rounded-t-(--sp-radius-md)
21
+ [&>*:last-child]:rounded-b-(--sp-radius-md)
22
+ ].freeze
23
+ }.freeze
24
+
25
+ private
26
+
27
+ def button_group_classes(layout: :inline)
28
+ {
29
+ classes: klasses(*LAYOUTS.fetch(layout, LAYOUTS[:inline]))
30
+ }
31
+ end
32
+ end
33
+ end
34
+ end
35
+ end
36
+ end
@@ -4,43 +4,126 @@ 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
- 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)
28
+ [--btn-bg:var(--sp-color-primary)]
29
+ [--btn-fg:var(--sp-color-primary-fg)]
30
+ [--btn-accent:var(--sp-color-primary)]
31
+ [--btn-border:var(--sp-color-primary-border)]
32
+ [--btn-ring:var(--sp-color-primary-ring)]
13
33
  ].freeze,
14
34
  secondary: %w[
15
- bg-(--sp-color-muted)
16
- text-(--sp-color-fg)
17
- hover:bg-(--sp-color-border)
35
+ [--btn-bg:var(--sp-color-secondary)]
36
+ [--btn-fg:var(--sp-color-secondary-fg)]
37
+ [--btn-accent:var(--sp-color-secondary)]
38
+ [--btn-border:var(--sp-color-secondary-border)]
39
+ [--btn-ring:var(--sp-color-secondary-ring)]
18
40
  ].freeze,
19
- outline: %w[
20
- border border-(--sp-color-border)
21
- bg-transparent
22
- text-(--sp-color-fg)
23
- hover:bg-(--sp-color-muted)
41
+ tertiary: %w[
42
+ [--btn-bg:var(--sp-color-muted)]
43
+ [--btn-fg:var(--sp-color-muted-fg)]
44
+ [--btn-accent:var(--sp-color-fg)]
45
+ [--btn-border:var(--sp-color-muted-border)]
46
+ [--btn-ring:var(--sp-color-muted-ring)]
47
+ ].freeze,
48
+ success: %w[
49
+ [--btn-bg:var(--sp-color-success)]
50
+ [--btn-fg:var(--sp-color-success-fg)]
51
+ [--btn-accent:var(--sp-color-success)]
52
+ [--btn-border:var(--sp-color-success-border)]
53
+ [--btn-ring:var(--sp-color-success-ring)]
24
54
  ].freeze,
25
55
  destructive: %w[
26
- bg-(--sp-color-destructive)
27
- text-(--sp-color-destructive-fg)
28
- hover:bg-(--sp-color-destructive)/90
56
+ [--btn-bg:var(--sp-color-destructive)]
57
+ [--btn-fg:var(--sp-color-destructive-fg)]
58
+ [--btn-accent:var(--sp-color-destructive)]
59
+ [--btn-border:var(--sp-color-destructive-border)]
60
+ [--btn-ring:var(--sp-color-destructive-ring)]
61
+ ].freeze,
62
+ warning: %w[
63
+ [--btn-bg:var(--sp-color-warning)]
64
+ [--btn-fg:var(--sp-color-warning-fg)]
65
+ [--btn-accent:var(--sp-color-warning)]
66
+ [--btn-border:var(--sp-color-warning-border)]
67
+ [--btn-ring:var(--sp-color-warning-ring)]
68
+ ].freeze,
69
+ info: %w[
70
+ [--btn-bg:var(--sp-color-info)]
71
+ [--btn-fg:var(--sp-color-info-fg)]
72
+ [--btn-accent:var(--sp-color-info)]
73
+ [--btn-border:var(--sp-color-info-border)]
74
+ [--btn-ring:var(--sp-color-info-ring)]
75
+ ].freeze
76
+ }.freeze
77
+
78
+ # ── Type styles ───────────────────────────────────────────────────────
79
+ TYPES = {
80
+ default: %w[
81
+ rounded-(--sp-radius-md)
82
+ bg-(--btn-bg) text-(--btn-fg)
83
+ border border-(--btn-border)
84
+ hover:bg-(--btn-bg)/90
85
+ ].freeze,
86
+ outline: %w[
87
+ rounded-(--sp-radius-md)
88
+ bg-(--sp-color-bg) text-(--btn-accent)
89
+ border border-(--btn-border)
90
+ hover:bg-(--btn-accent)/10
91
+ ].freeze,
92
+ ghost: %w[
93
+ rounded-(--sp-radius-md)
94
+ bg-transparent text-(--btn-accent)
95
+ border border-transparent
96
+ hover:bg-(--btn-accent)/10
29
97
  ].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
98
  fab: %w[
33
- rounded-full shadow-lg
34
- bg-(--sp-color-primary) text-(--sp-color-primary-fg)
35
- hover:bg-(--sp-color-primary)/90 hover:shadow-xl
99
+ rounded-(--sp-radius-full)
100
+ bg-(--btn-bg) text-(--btn-fg)
101
+ border border-(--btn-border)
102
+ shadow-(--sp-shadow-lg)
103
+ hover:bg-(--btn-bg)/90 hover:shadow-(--sp-shadow-xl)
104
+ ].freeze,
105
+ fab_outline: %w[
106
+ rounded-(--sp-radius-full)
107
+ bg-transparent text-(--btn-accent)
108
+ border border-(--btn-border)
109
+ shadow-(--sp-shadow-lg)
110
+ hover:bg-(--btn-bg) hover:text-(--btn-fg) hover:shadow-(--sp-shadow-xl)
36
111
  ].freeze,
37
112
  dashed: %w[
38
- border border-dashed border-(--sp-color-border)
39
- bg-transparent text-(--sp-color-fg)
40
- hover:bg-(--sp-color-muted)
113
+ rounded-(--sp-radius-md)
114
+ bg-(--sp-color-bg) text-(--btn-accent)
115
+ border border-dashed border-(--btn-border)
116
+ hover:bg-(--btn-accent)/10
117
+ ].freeze,
118
+ card: %w[
119
+ rounded-(--sp-radius-md)
120
+ bg-(--sp-color-bg) text-(--btn-accent)
121
+ border border-(--btn-border) shadow-(--sp-shadow-xs)
122
+ hover:bg-(--btn-accent)/10
41
123
  ].freeze
42
124
  }.freeze
43
125
 
126
+ # ── Sizes ─────────────────────────────────────────────────────────────
44
127
  SIZES = {
45
128
  xs: %w[h-7 px-(--sp-space-2) text-(length:--sp-text-xs)].freeze,
46
129
  sm: %w[h-8 px-(--sp-space-3) text-(length:--sp-text-sm)].freeze,
@@ -49,55 +132,22 @@ module StimulusPlumbers
49
132
  xl: %w[h-14 px-(--sp-space-6) text-(length:--sp-text-lg)].freeze
50
133
  }.freeze
51
134
 
52
- FLEX_ALIGN = {
53
- row: {
54
- left: "justify-start",
55
- center: %w[justify-center items-center].freeze,
56
- right: "justify-end",
57
- top: "items-start",
58
- bottom: "items-end"
59
- }.freeze,
60
- col: {
61
- top: "justify-start",
62
- center: %w[justify-center items-center].freeze,
63
- bottom: "justify-end",
64
- left: "items-start",
65
- right: "items-end"
66
- }.freeze
67
- }.freeze
68
-
69
- BASE = %w[
70
- inline-flex items-center justify-center gap-(--sp-space-2) font-medium
71
- rounded-(--sp-radius-md) transition-colors
72
- focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-offset-2
73
- disabled:pointer-events-none disabled:opacity-50
74
- ].freeze
75
-
76
- GROUP_BASE = %w[flex gap-(--sp-space-2)].freeze
77
-
78
135
  private
79
136
 
80
- def button_classes(variant: :primary, size: :md)
137
+ def button_classes(type: :default, variant: :primary, size: :md)
81
138
  {
82
139
  classes: klasses(
83
140
  *BASE,
84
- *VARIANTS.fetch(variant, []),
85
- *SIZES.fetch(size, [])
86
- )
87
- }
88
- end
89
-
90
- def button_group_classes(alignment: :left, direction: :row)
91
- {
92
- classes: klasses(
93
- *GROUP_BASE,
94
- *Array(FLEX_ALIGN.dig(direction, alignment))
141
+ *(type == :card ? CARD : LAYOUT),
142
+ *VARIANTS.fetch(variant, VARIANTS[:primary]),
143
+ *TYPES.fetch(type, TYPES[:default]),
144
+ *(type == :card ? [] : SIZES.fetch(size, []))
95
145
  )
96
146
  }
97
147
  end
98
148
 
99
149
  def button_icon_classes
100
- { classes: klasses("size-(--sp-control-size)", "stroke-current") }
150
+ { classes: klasses("size-(--sp-icon-size-sm)", "stroke-current") }
101
151
  end
102
152
  end
103
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,22 +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
+ aria-[hidden=true]:pointer-events-none
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
24
31
  ].freeze
25
32
 
26
- NAV = %w[flex items-center justify-between gap-(--sp-space-1) mb-(--sp-space-2)].freeze
33
+ QUARTER_GRID = %w[grid grid-cols-4 gap-(--sp-space-1)].freeze
27
34
 
28
- NAV_BTN = %w[
29
- inline-flex items-center justify-center
30
- size-(--sp-calendar-day-size) rounded-(--sp-radius-md)
31
- text-(--sp-color-fg) hover:bg-(--sp-color-muted)
32
- focus-visible:outline-none focus-visible:ring-2
33
- focus-visible:ring-(--sp-focus-ring-color)
34
- disabled:pointer-events-none disabled:opacity-50
35
+ MONTHS_OF_YEAR = "contents"
36
+
37
+ MONTH = %w[
38
+ rounded-(--sp-radius-md) flex items-center justify-center
39
+ text-(length:--sp-text-sm) h-10 flex-1 px-(--sp-space-2)
40
+ hover:bg-(--sp-color-muted) cursor-pointer
41
+ aria-selected:bg-(--sp-color-primary)
42
+ aria-selected:text-(--sp-color-primary-fg)
43
+ aria-selected:hover:bg-(--sp-color-primary)/90
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
49
+ ].freeze
50
+
51
+ YEARS_OF_DECADE = "contents"
52
+
53
+ YEAR = %w[
54
+ rounded-(--sp-radius-md) flex items-center justify-center
55
+ text-(length:--sp-text-sm) h-10 flex-1 px-(--sp-space-2)
56
+ hover:bg-(--sp-color-muted) cursor-pointer
57
+ aria-selected:bg-(--sp-color-primary)
58
+ aria-selected:text-(--sp-color-primary-fg)
59
+ aria-selected:hover:bg-(--sp-color-primary)/90
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
35
65
  ].freeze
36
66
 
37
67
  private
@@ -44,29 +74,33 @@ module StimulusPlumbers
44
74
  { classes: klasses(*DAYS_OF_WEEK) }
45
75
  end
46
76
 
47
- def calendar_week_classes
48
- { classes: "contents" }
49
- end
50
-
51
77
  def calendar_days_of_month_classes
52
78
  { classes: klasses(*DAYS_OF_MONTH) }
53
79
  end
54
80
 
55
- def calendar_day_classes(outside: false)
56
- {
57
- classes: klasses(
58
- *DAY,
59
- *(outside ? %w[text-(--sp-color-muted-fg) opacity-50] : [])
60
- )
61
- }
81
+ def calendar_months_of_year_classes
82
+ { classes: MONTHS_OF_YEAR }
83
+ end
84
+
85
+ def calendar_years_of_decade_classes
86
+ { classes: YEARS_OF_DECADE }
87
+ end
88
+
89
+ def calendar_row_classes
90
+ { classes: "contents" }
62
91
  end
63
92
 
64
- def calendar_navigation_classes
65
- { classes: klasses(*NAV) }
93
+ def calendar_day_classes(outside: false, **)
94
+ extra = outside ? %w[text-(--sp-color-muted-fg)] : []
95
+ { classes: klasses(*DAY, *extra) }
66
96
  end
67
97
 
68
- def calendar_navigation_navigator_classes
69
- { classes: klasses(*NAV_BTN) }
98
+ def calendar_month_classes(**) = { classes: klasses(*MONTH) }
99
+
100
+ def calendar_year_classes(**) = { classes: klasses(*YEAR) }
101
+
102
+ def calendar_quarter_grid_classes
103
+ { classes: klasses(*QUARTER_GRID) }
70
104
  end
71
105
  end
72
106
  end
@@ -5,19 +5,51 @@ module StimulusPlumbers
5
5
  module Tailwind
6
6
  module Card
7
7
  BASE = %w[
8
- rounded-(--sp-radius-lg) border border-(--sp-color-border)
9
- bg-(--sp-color-bg) shadow-(--sp-shadow-sm)
8
+ flex flex-col
9
+ rounded-(--sp-radius-md) border border-(--card-ring)
10
+ bg-(--sp-color-bg) shadow-(--sp-shadow-xs)
10
11
  ].freeze
11
12
 
13
+ VARIANTS = {
14
+ primary: %w[[--card-ring:var(--sp-color-primary)]].freeze,
15
+ secondary: %w[[--card-ring:var(--sp-color-secondary)]].freeze,
16
+ tertiary: %w[[--card-ring:var(--sp-color-muted-fg)]].freeze,
17
+ success: %w[[--card-ring:var(--sp-color-success)]].freeze,
18
+ destructive: %w[[--card-ring:var(--sp-color-destructive)]].freeze,
19
+ warning: %w[[--card-ring:var(--sp-color-warning)]].freeze,
20
+ info: %w[[--card-ring:var(--sp-color-info)]].freeze
21
+ }.freeze
22
+
23
+ HEADER_BASE = %w[
24
+ flex items-center gap-(--sp-space-3)
25
+ px-(--sp-space-6) py-(--sp-space-6)
26
+ ].freeze
27
+
28
+ ICON_BASE = %w[
29
+ size-(--sp-space-6) shrink-0 stroke-current text-(--sp-color-muted-fg)
30
+ ].freeze
31
+
32
+ TITLE_BASE = %w[
33
+ text-(length:--sp-text-base) font-semibold text-(--sp-color-fg)
34
+ ].freeze
35
+
36
+ BODY_BASE = %w[
37
+ px-(--sp-space-6) py-(--sp-space-3)
38
+ ].freeze
39
+
40
+ ACTION_BASE = %w[w-full justify-start].freeze
41
+
12
42
  private
13
43
 
14
- def card_classes
15
- { classes: klasses(*BASE) }
44
+ def card_classes(variant: :tertiary)
45
+ { classes: klasses(*VARIANTS.fetch(variant, VARIANTS[:tertiary]), *BASE) }
16
46
  end
17
47
 
18
- def card_section_classes
19
- { classes: klasses("p-(--sp-space-6)") }
20
- end
48
+ def card_header_classes = { classes: klasses(*HEADER_BASE) }
49
+ def card_icon_classes = { classes: klasses(*ICON_BASE) }
50
+ def card_title_classes = { classes: klasses(*TITLE_BASE) }
51
+ def card_body_classes = { classes: klasses(*BODY_BASE) }
52
+ def card_action_classes = { classes: klasses(*ACTION_BASE) }
21
53
  end
22
54
  end
23
55
  end