nitro_kit 0.1.0 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (74) hide show
  1. checksums.yaml +4 -4
  2. data/MIT-LICENSE +20 -0
  3. data/README.md +28 -1
  4. data/Rakefile +6 -4
  5. data/app/components/nitro_kit/accordion.rb +69 -33
  6. data/app/components/nitro_kit/alert.rb +69 -0
  7. data/app/components/nitro_kit/avatar.rb +52 -0
  8. data/app/components/nitro_kit/badge.rb +47 -23
  9. data/app/components/nitro_kit/button.rb +97 -65
  10. data/app/components/nitro_kit/button_group.rb +18 -13
  11. data/app/components/nitro_kit/card.rb +49 -9
  12. data/app/components/nitro_kit/checkbox.rb +59 -41
  13. data/app/components/nitro_kit/checkbox_group.rb +38 -0
  14. data/app/components/nitro_kit/combobox.rb +138 -0
  15. data/app/components/nitro_kit/component.rb +46 -17
  16. data/app/components/nitro_kit/datepicker.rb +9 -0
  17. data/app/components/nitro_kit/dialog.rb +95 -0
  18. data/app/components/nitro_kit/dropdown.rb +116 -73
  19. data/app/components/nitro_kit/field.rb +281 -30
  20. data/app/components/nitro_kit/field_group.rb +10 -5
  21. data/app/components/nitro_kit/fieldset.rb +42 -7
  22. data/app/components/nitro_kit/form_builder.rb +45 -22
  23. data/app/components/nitro_kit/icon.rb +29 -8
  24. data/app/components/nitro_kit/input.rb +26 -0
  25. data/app/components/nitro_kit/label.rb +18 -5
  26. data/app/components/nitro_kit/pagination.rb +98 -0
  27. data/app/components/nitro_kit/radio_button.rb +28 -27
  28. data/app/components/nitro_kit/radio_button_group.rb +53 -0
  29. data/app/components/nitro_kit/select.rb +72 -0
  30. data/app/components/nitro_kit/switch.rb +49 -39
  31. data/app/components/nitro_kit/table.rb +56 -0
  32. data/app/components/nitro_kit/tabs.rb +98 -0
  33. data/app/components/nitro_kit/textarea.rb +26 -0
  34. data/app/components/nitro_kit/toast.rb +104 -0
  35. data/app/components/nitro_kit/tooltip.rb +53 -0
  36. data/app/helpers/nitro_kit/accordion_helper.rb +3 -1
  37. data/app/helpers/nitro_kit/alert_helper.rb +11 -0
  38. data/app/helpers/nitro_kit/avatar_helper.rb +9 -0
  39. data/app/helpers/nitro_kit/badge_helper.rb +3 -5
  40. data/app/helpers/nitro_kit/button_group_helper.rb +2 -0
  41. data/app/helpers/nitro_kit/button_helper.rb +37 -28
  42. data/app/helpers/nitro_kit/card_helper.rb +2 -0
  43. data/app/helpers/nitro_kit/checkbox_helper.rb +19 -16
  44. data/app/helpers/nitro_kit/combobox_helper.rb +9 -0
  45. data/app/helpers/nitro_kit/datepicker_helper.rb +9 -0
  46. data/app/helpers/nitro_kit/dialog_helper.rb +9 -0
  47. data/app/helpers/nitro_kit/dropdown_helper.rb +3 -1
  48. data/app/helpers/nitro_kit/field_group_helper.rb +9 -0
  49. data/app/helpers/nitro_kit/field_helper.rb +4 -2
  50. data/app/helpers/nitro_kit/fieldset_helper.rb +9 -0
  51. data/app/helpers/nitro_kit/form_helper.rb +13 -0
  52. data/app/helpers/nitro_kit/icon_helper.rb +3 -1
  53. data/app/helpers/nitro_kit/input_helper.rb +35 -0
  54. data/app/helpers/nitro_kit/label_helper.rb +12 -8
  55. data/app/helpers/nitro_kit/pagination_helper.rb +42 -0
  56. data/app/helpers/nitro_kit/radio_button_helper.rb +15 -12
  57. data/app/helpers/nitro_kit/select_helper.rb +24 -0
  58. data/app/helpers/nitro_kit/switch_helper.rb +4 -10
  59. data/app/helpers/nitro_kit/table_helper.rb +9 -0
  60. data/app/helpers/nitro_kit/tabs_helper.rb +9 -0
  61. data/app/helpers/nitro_kit/textarea_helper.rb +9 -0
  62. data/app/helpers/nitro_kit/toast_helper.rb +36 -0
  63. data/app/helpers/nitro_kit/tooltip_helper.rb +9 -0
  64. data/lib/generators/nitro_kit/add_generator.rb +38 -41
  65. data/lib/generators/nitro_kit/install_generator.rb +2 -1
  66. data/lib/nitro_kit/engine.rb +4 -0
  67. data/lib/nitro_kit/schema_builder.rb +90 -16
  68. data/lib/nitro_kit/version.rb +1 -1
  69. data/lib/nitro_kit.rb +39 -1
  70. data/lib/tasks/nitro_kit_tasks.rake +4 -0
  71. metadata +40 -12
  72. data/app/components/nitro_kit/radio_group.rb +0 -35
  73. data/app/helpers/application_helper.rb +0 -89
  74. data/lib/nitro_kit/railtie.rb +0 -8
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 738be78aa004f1a57e3b2f1b4f4c72b7e11b055e0e8a543db2205c414e785b60
4
- data.tar.gz: 60d0b5bf5afa57cf8710838f13f5f586c18dc48ad04f7e503ec362c3ea372cc0
3
+ metadata.gz: 6d58e573f0c99860c6ede6591c772db3d2399c754a1cb2c25b65632c42ca8a00
4
+ data.tar.gz: 4796fae213b057ed86d3bcc693c504c7323abe020bcfa920713ea7d9a2e4438a
5
5
  SHA512:
6
- metadata.gz: 6a9e5e794e437dc0e27765affc79414ca3caf90c4aa5747929d93db3b4e7a2ef2fda41f01758af31ca5ea6c0431f9615de3c241faca1fc90be0b243499884bdc
7
- data.tar.gz: ed4904af0e0499b2c947baf1e0c7016e2a134a8045288311b05eefe8aaac30985ebc0da85cbf5e47b97548dd650eec0155ba1ee6b3ef84c23e51a45203bbbc23
6
+ metadata.gz: 2865c2a1a86d6cf786eff5a699ce98aabea646c44349ecb387369ee7ba3aaab1b928f28ea1fded788bc95ffeb06926aac017a4fe292e70bbc0e1ecfa7d0dc30f
7
+ data.tar.gz: 2f8f3fc20b0be34cc8fc07f01fba9ace962dad39926332a50bf65bec062b7d96398bdc790b708fb6c027f2193b542641c5127fd6920f417d359a448a82bff782
data/MIT-LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright Mikkel Malmberg
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md CHANGED
@@ -1 +1,28 @@
1
- _Nothing to see here yet, move along_
1
+ <center><a href="https://nitrokit.dev"><img src="https://s3.brnbw.com/Artboard-q85JFfA8Auat32ByIAXtDAsbYGgs5MeTM4GDaonKhlxVniioPDLQTZUeynCfdBSHAfiRYhMWkGaYZC9ClkZS9aFgkBjx9mrAmnFs.png" alt="Nitro Kit" width="335" /></a></center>
2
+
3
+ <p></p>
4
+
5
+ **Nitro Kit** is a set of **generic UI components** to help you build your **Ruby on Rails** application.
6
+
7
+ Rather than being fancy it is **purposefully modest**. Instead of giving you a black box, it is provided as a bunch of generators that give you a starting point to build upon.
8
+
9
+ Easy to customize, accessible, Rails native.
10
+
11
+ _Nitro Kit is still pre 1.0 and is in active development._
12
+
13
+ See [nitrokit.dev](https://nitrokit.dev).
14
+
15
+ [![Rubygems](https://img.shields.io/gem/v/nitro_kit.svg)](https://rubygems.org/gems/nitro_kit)
16
+
17
+ ---
18
+
19
+ ### Development
20
+
21
+ ```sh
22
+ bin/setup
23
+ bin/dev
24
+ ```
25
+
26
+ ### License
27
+
28
+ MIT
data/Rakefile CHANGED
@@ -1,6 +1,8 @@
1
- # Add your own tasks in files placed in lib/tasks ending in .rake,
2
- # for example lib/tasks/capistrano.rake, and they will automatically be available to Rake.
1
+ require "bundler/setup"
3
2
 
4
- require_relative "config/application"
3
+ APP_RAKEFILE = File.expand_path("test/dummy/Rakefile", __dir__)
4
+ load "rails/tasks/engine.rake"
5
5
 
6
- Rails.application.load_tasks
6
+ load "rails/tasks/statistics.rake"
7
+
8
+ require "bundler/gem_tasks"
@@ -1,27 +1,17 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module NitroKit
2
4
  class Accordion < Component
3
- ITEM = "divide-y"
4
-
5
- TRIGGER = [
6
- "flex w-full items-center justify-between py-4 font-medium cursor-pointer",
7
- "group/accordion-trigger hover:underline transition-colors",
8
- "[&[aria-expanded='true']>svg]:rotate-180",
9
- "focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2"
10
- ].freeze
11
-
12
- CONTENT = [
13
- "overflow-hidden transition-all duration-200",
14
- "[&[aria-hidden='true']]:h-0 [&[aria-hidden='false']]:h-auto"
15
- ].freeze
16
-
17
- ARROW = "transition-transform duration-200 text-muted-foreground group-hover/accordion-trigger:text-primary"
5
+ def initialize(**attrs)
6
+ super(
7
+ attrs,
8
+ class: item_class,
9
+ data: {controller: "nk--accordion"}
10
+ )
11
+ end
18
12
 
19
13
  def view_template
20
- div(
21
- **attrs,
22
- class: merge([ITEM, class_list]),
23
- data: { controller: "nk--accordion" }
24
- ) do
14
+ div(**attrs) do
25
15
  yield
26
16
  end
27
17
  end
@@ -34,27 +24,73 @@ module NitroKit
34
24
 
35
25
  def trigger(text = nil, **attrs)
36
26
  button(
37
- type: "button",
38
- class: TRIGGER,
39
- data: {
40
- action: "nk--accordion#toggle",
41
- "nk--accordion-target": "trigger"
42
- },
43
- aria: { expanded: "false", controls: "content" }
27
+ **mattr(
28
+ attrs,
29
+ type: "button",
30
+ class: trigger_class,
31
+ data: {
32
+ action: "nk--accordion#toggle",
33
+ nk__accordion_target: "trigger"
34
+ },
35
+ aria: {expanded: "false"}
36
+ )
44
37
  ) do
45
- div(**attrs) { text || yield }
46
- render NitroKit::Icon.new(name: "chevron-down", class: ARROW)
38
+ block_given? ? yield : plain(text)
39
+ chevron_icon
47
40
  end
48
41
  end
49
42
 
50
43
  def content(**attrs)
51
44
  div(
52
- class: merge(CONTENT),
53
- data: { "nk--accordion-target": "content" },
54
- aria: { hidden: "true" }
45
+ **mattr(
46
+ attrs,
47
+ class: content_class,
48
+ data: {
49
+ nk__accordion_target: "content"
50
+ },
51
+ aria: {hidden: "true"}
52
+ )
55
53
  ) do
56
54
  div(class: "pb-4") { yield }
57
55
  end
58
56
  end
57
+
58
+ private
59
+
60
+ def item_class
61
+ "divide-y"
62
+ end
63
+
64
+ def trigger_class
65
+ [
66
+ "flex w-full items-center justify-between py-4 font-medium cursor-pointer",
67
+ "group/accordion-trigger hover:underline transition-colors",
68
+ "[&[aria-expanded='true']>svg]:rotate-180",
69
+ "focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2"
70
+ ]
71
+ end
72
+
73
+ def content_class
74
+ [
75
+ "overflow-hidden transition-all duration-200",
76
+ "[&[aria-hidden='true']]:h-0 [&[aria-hidden='false']]:h-auto"
77
+ ]
78
+ end
79
+
80
+ def arrow_class
81
+ "transition-transform duration-200 text-muted-foreground group-hover/accordion-trigger:text-primary"
82
+ end
83
+
84
+ def chevron_icon
85
+ svg(
86
+ class: "transition-transform duration-200 size-4 self-center place-self-end mr-2 pointer-events-none text-muted-foreground group-hover/accordion-trigger:text-primary",
87
+ viewbox: "0 0 24 24",
88
+ fill: "none",
89
+ stroke: "currentColor",
90
+ stroke_width: 1
91
+ ) do |svg|
92
+ svg.path(d: "m6 9 6 6 6-6")
93
+ end
94
+ end
59
95
  end
60
- end
96
+ end
@@ -0,0 +1,69 @@
1
+ # frozen_string_literal: true
2
+
3
+ module NitroKit
4
+ class Alert < Component
5
+ VARIANTS = %i[default warning error success]
6
+
7
+ def initialize(variant: :default, **attrs)
8
+ @variant = variant
9
+
10
+ super(
11
+ attrs,
12
+ role: "alert",
13
+ class: [base_class, variant_class]
14
+ )
15
+ end
16
+
17
+ attr_reader :variant
18
+
19
+ def view_template
20
+ div(**attrs) do
21
+ yield
22
+ end
23
+ end
24
+
25
+ def title(text = nil, **attrs, &block)
26
+ h5(**mattr(attrs, class: title_class)) do
27
+ text_or_block(text, &block)
28
+ end
29
+ end
30
+
31
+ def description(text = nil, **attrs, &block)
32
+ div(**mattr(attrs, class: description_class)) do
33
+ text_or_block(text, &block)
34
+ end
35
+ end
36
+
37
+ private
38
+
39
+ def base_class
40
+ [
41
+ "relative border w-full rounded-md p-5 text-sm space-y-2",
42
+ "[&>svg~*]:pl-8 [&>svg]:absolute [&>svg]:top-5 [&>svg]:left-5"
43
+ ]
44
+ end
45
+
46
+ def variant_class
47
+ case variant
48
+ when :default
49
+ "border-border bg-background text-foreground"
50
+ when :warning
51
+ "bg-yellow-300/20 dark:bg-yellow-300/20 text-yellow-900 dark:text-yellow-100 border-yellow-500/80 dark:border-yellow-400/50"
52
+ when :success
53
+ "bg-green-300/20 dark:bg-green-300/20 text-green-900 dark:text-green-100 border-green-500/80 dark:border-green-400/50"
54
+ when :error
55
+ "bg-red-300/20 dark:bg-red-300/20 text-red-900 dark:text-red-100 border-red-400/80 dark:border-red-400/50"
56
+ else
57
+ raise ArgumentError, "Invalid variant: #{variant}"
58
+ end
59
+ end
60
+
61
+ def title_class
62
+ "font-medium text-lg leading-5"
63
+ end
64
+
65
+ def description_class
66
+ ""
67
+ end
68
+ end
69
+ end
@@ -0,0 +1,52 @@
1
+ # frozen_string_literal: true
2
+
3
+ module NitroKit
4
+ class Avatar < Component
5
+ include ActionView::Helpers::AssetUrlHelper
6
+
7
+ def initialize(src_arg = nil, src: nil, size: :md, **attrs)
8
+ @src = src_arg || src
9
+ @size = size
10
+
11
+ super(
12
+ attrs,
13
+ class: [container_class, size_classes]
14
+ )
15
+ end
16
+
17
+ attr_reader :src, :size
18
+
19
+ def view_template(&block)
20
+ div(**attrs) do
21
+ image
22
+ end
23
+ end
24
+
25
+ def image
26
+ helpers.image_tag(src, class: image_class)
27
+ end
28
+
29
+ private
30
+
31
+ def size_classes
32
+ case size
33
+ when :sm
34
+ "size-8"
35
+ when :md
36
+ "size-12"
37
+ when :lg
38
+ "size-16"
39
+ else
40
+ raise ArgumentError, "Invalid size: #{size}"
41
+ end
42
+ end
43
+
44
+ def container_class
45
+ "inline-flex overflow-hidden rounded-full"
46
+ end
47
+
48
+ def image_class
49
+ "block size-full bg-muted"
50
+ end
51
+ end
52
+ end
@@ -1,34 +1,58 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module NitroKit
2
4
  class Badge < Component
3
- BASE = "inline-flex items-center gap-x-1.5 rounded-md font-medium"
4
-
5
- VARIANTS = {
6
- default: "border border-transparent bg-zinc-200 text-zinc-700 dark:bg-zinc-800 dark:text-zinc-300",
7
- outline: "border"
8
- }
9
-
10
- SIZES = {
11
- sm: "text-xs px-1.5 py-0.5",
12
- md: "text-sm px-2 py-0.5"
13
- }
14
-
15
- def initialize(variant: :default, size: :md, **attrs)
16
- @attrs = attrs
17
-
18
- @class_list = merge(
19
- [
20
- BASE,
21
- VARIANTS[variant],
22
- SIZES[size],
23
- attrs[:class]
5
+ VARIANTS = %i[default outline]
6
+
7
+ def initialize(text = nil, variant: :default, size: :md, **attrs)
8
+ @text = text
9
+ @variant = variant
10
+ @size = size
11
+
12
+ super(
13
+ attrs,
14
+ class: [
15
+ base_class,
16
+ variant_class,
17
+ size_class
24
18
  ]
25
19
  )
26
20
  end
27
21
 
28
- attr_reader :color, :attrs, :class_list
22
+ attr_reader :text, :variant, :size
29
23
 
30
24
  def view_template(&block)
31
- span(**attrs, class: class_list, &block)
25
+ span(**attrs) do
26
+ text_or_block(text, &block)
27
+ end
28
+ end
29
+
30
+ private
31
+
32
+ def base_class
33
+ "inline-flex items-center gap-x-1.5 rounded-md font-medium"
34
+ end
35
+
36
+ def variant_class
37
+ case variant
38
+ when :default
39
+ "bg-zinc-200 text-zinc-700 dark:bg-zinc-800 dark:text-zinc-300"
40
+ when :outline
41
+ "border"
42
+ else
43
+ raise ArgumentError, "Invalid variant: #{variant}"
44
+ end
45
+ end
46
+
47
+ def size_class
48
+ case size
49
+ when :sm
50
+ "text-xs px-1.5 py-0.5"
51
+ when :md
52
+ "text-sm px-2 py-0.5"
53
+ else
54
+ raise ArgumentError, "Invalid size: #{size}"
55
+ end
32
56
  end
33
57
  end
34
58
  end
@@ -1,89 +1,51 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module NitroKit
2
4
  class Button < Component
3
- BASE = [
4
- "inline-flex items-center cursor-pointer shrink-0 justify-center rounded-md border gap-2 font-medium",
5
- # Disabled
6
- "disabled:opacity-70 disabled:pointer-events-none",
7
- # Focus
8
- "focus:outline-none focus:ring-[3px] focus:ring-offset-2 focus:ring-ring ring-offset-background",
9
- # Icon
10
- "[&_svg]:size-4 [&_svg]:pointer-events-none [&_svg]:shrink-0",
11
- # If icon only, make square
12
- "[&_svg:first-child:last-child]:-mx-2"
13
- ].freeze
14
-
15
- VARIANTS = {
16
- default: [
17
- "bg-background text-foreground",
18
- "hover:bg-zinc-50 dark:hover:bg-zinc-900"
19
- ],
20
- primary: [
21
- "bg-primary text-white dark:text-zinc-950 border-primary",
22
- "hover:bg-primary/90 dark:hover:bg-primary/90"
23
- ],
24
- destructive: [
25
- "bg-destructive text-white border-destructive",
26
- "hover:bg-destructive/90 dark:hover:bg-destructive/90",
27
- "disabled:text-white/80"
28
- ],
29
- ghost: [
30
- "bg-transparent text-foreground border-transparent",
31
- "hover:bg-zinc-50 dark:hover:bg-zinc-900",
32
- "disabled:text-muted-foreground"
33
- ]
34
- }.freeze
35
-
36
- SIZES = {
37
- base: "px-4 h-9",
38
- sm: "px-2.5 h-7 text-sm",
39
- xs: "px-1.5 h-6 text-xs"
40
- }
5
+ VARIANTS = %i[default primary destructive ghost]
41
6
 
42
7
  def initialize(
8
+ text = nil,
43
9
  href: nil,
10
+ variant: :default,
11
+ size: :md,
44
12
  icon: nil,
45
13
  icon_right: nil,
46
- size: :base,
47
- type: :button,
48
- variant: :default,
49
14
  **attrs
50
15
  )
16
+ @text = text
51
17
  @href = href
52
18
  @icon = icon
53
19
  @icon_right = icon_right
54
20
  @size = size
55
- @type = type
56
21
  @variant = variant
57
- @attrs = attrs
58
22
 
59
- @class_list = merge(
60
- [
61
- BASE,
62
- VARIANTS[variant],
63
- SIZES[size],
64
- attrs[:class]
23
+ super(
24
+ attrs,
25
+ class: [
26
+ base_class,
27
+ variant_class,
28
+ size_class
65
29
  ]
66
30
  )
67
31
  end
68
32
 
69
33
  attr_reader(
70
- :class_list,
34
+ :text,
71
35
  :href,
72
36
  :icon,
73
37
  :icon_right,
74
38
  :size,
75
- :type,
76
- :variant,
77
- :attrs
39
+ :variant
78
40
  )
79
41
 
80
42
  def view_template(&block)
81
43
  if href
82
- a(href:, **attrs, class: class_list) do
44
+ a(href:, **attrs) do
83
45
  contents(&block)
84
46
  end
85
47
  else
86
- button(type:, **attrs, class: class_list) do
48
+ button(type: :button, **attrs) do
87
49
  contents(&block)
88
50
  end
89
51
  end
@@ -91,19 +53,89 @@ module NitroKit
91
53
 
92
54
  private
93
55
 
94
- def contents
95
- text = safe(capture { yield })
96
- has_text = text.to_s.present?
56
+ def contents(&block)
57
+ has_content = text.present? || block_given?
58
+
59
+ if !has_content
60
+ return render(Icon.new(icon))
61
+ end
62
+
63
+ render(Icon.new(icon)) if icon
64
+
65
+ if block_given?
66
+ yield
67
+ else
68
+ span { plain(text) }
69
+ end
70
+
71
+ render(Icon.new(icon_right)) if icon_right
72
+ end
73
+
74
+ def base_class
75
+ [
76
+ "inline-flex items-center cursor-pointer shrink-0 justify-center rounded-md border gap-2 font-medium select-none",
77
+ # Disabled
78
+ "disabled:opacity-70 disabled:pointer-events-none",
79
+ # Focus
80
+ "focus-visible:outline-none focus-visible:ring-[3px] focus-visible:ring-offset-2 focus-visible:ring-ring ring-offset-background",
81
+ # Icon
82
+ "[&_svg]:pointer-events-none [&_svg]:shrink-0"
83
+ ]
84
+ end
97
85
 
98
- if !icon && has_text && !icon_right
99
- return text
100
- elsif icon && !has_text && !icon_right
101
- return render(Icon.new(name: icon))
86
+ def variant_class
87
+ case variant
88
+ when :default
89
+ [
90
+ "bg-background text-foreground border-border",
91
+ "hover:bg-zinc-50 dark:hover:bg-zinc-900"
92
+ ]
93
+ when :primary
94
+ [
95
+ "bg-primary text-white dark:text-zinc-950 border-primary",
96
+ "hover:bg-primary/90 dark:hover:bg-primary/90"
97
+ ]
98
+ when :destructive
99
+ [
100
+ "bg-destructive text-white border-destructive",
101
+ "hover:bg-destructive/90 dark:hover:bg-destructive/90",
102
+ "disabled:text-white/80"
103
+ ]
104
+ when :ghost
105
+ [
106
+ "bg-transparent text-foreground border-transparent",
107
+ "hover:bg-zinc-200/50 dark:hover:bg-zinc-900",
108
+ "disabled:text-muted-foreground"
109
+ ]
110
+ else
111
+ raise ArgumentError, "Unknown variant `#{variant}'"
102
112
  end
113
+ end
103
114
 
104
- render(Icon.new(name: icon)) if icon
105
- span { text }
106
- render(Icon.new(name: icon_right)) if icon_right
115
+ def size_class
116
+ case size
117
+ when :xs
118
+ "px-1.5 h-6 text-xs [&_svg]:size-3"
119
+ when :sm
120
+ [
121
+ "px-2.5 h-7 text-sm [&_svg]:size-3",
122
+ "[&_svg:first-child:last-child]:-mx-1"
123
+ ]
124
+ when :md
125
+ [
126
+ "px-4 h-10 text-base [&_svg]:size-4",
127
+ # If icon only, make square
128
+ "[&_svg:first-child:last-child]:-mx-2"
129
+ ]
130
+ when :lg
131
+ [
132
+ "px-5 h-11 text-lg [&_svg]:size-5",
133
+ # If icon only, make square
134
+ "[&_svg:first-child:last-child]:-mx-2"
135
+ ]
136
+ else
137
+ raise ArgumentError, "Unknown size `#{size}'"
138
+ end
107
139
  end
108
140
  end
109
141
  end
@@ -1,19 +1,24 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module NitroKit
2
4
  class ButtonGroup < Component
3
- def view_template(&block)
4
- div(
5
- class: merge(
6
- [
7
- "flex -space-x-px isolate",
8
- # Remove rounded corners from middle buttons
9
- "[&>*:not(:first-child):not(:last-child)]:rounded-none [&>*:first-child:not(:last-child)]:rounded-r-none [&>*:last-child:not(:first-child)]:rounded-l-none",
10
- # Put focused button on top
11
- "[&>*]:focus:z-10",
12
- attrs[:class]
13
- ]
14
- ),
15
- &block
5
+ def initialize(**attrs)
6
+ super(
7
+ attrs,
8
+ class: [
9
+ "flex -space-x-px isolate",
10
+ # Remove rounded corners from middle buttons
11
+ "[&>*:not(:first-child):not(:last-child)]:rounded-none [&>*:first-child:not(:last-child)]:rounded-r-none [&>*:last-child:not(:first-child)]:rounded-l-none",
12
+ # Put focused button on top
13
+ "[&>*]:focus:z-10"
14
+ ]
16
15
  )
17
16
  end
17
+
18
+ def view_template
19
+ div(**attrs) do
20
+ yield
21
+ end
22
+ end
18
23
  end
19
24
  end