cubit_components 0.1.0 → 0.2.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 +4 -4
- data/README.md +20 -43
- data/Rakefile +8 -5
- data/lib/cubit_components/base_component.rb +48 -19
- data/lib/cubit_components/box_component.rb +1 -3
- data/lib/cubit_components/configuration.rb +16 -8
- data/lib/cubit_components/container_component.rb +11 -0
- data/lib/cubit_components/flex_component.rb +17 -0
- data/lib/cubit_components/grid_component.rb +16 -0
- data/lib/cubit_components/hstack_component.rb +12 -0
- data/lib/cubit_components/page_component.rb +11 -27
- data/lib/cubit_components/page_container_component.rb +27 -0
- data/lib/cubit_components/placeholder_component.rb +36 -0
- data/lib/cubit_components/spread_component.rb +9 -54
- data/lib/cubit_components/stack_component.rb +7 -25
- data/lib/cubit_components/style_dsl.rb +53 -0
- data/lib/cubit_components/version.rb +3 -1
- data/lib/cubit_components/vstack_component.rb +12 -0
- data/lib/cubit_components.rb +11 -24
- data/sig/cubit_components.rbs +4 -0
- metadata +23 -156
- data/MIT-LICENSE +0 -20
- data/app/assets/stylesheets/cubit_components/application.css +0 -6
- data/app/assets/tailwind/cubit_components/engine.css +0 -4
- data/config/routes.rb +0 -2
- data/lib/cubit_components/bleed_component.rb +0 -26
- data/lib/cubit_components/columns_component.rb +0 -48
- data/lib/cubit_components/content_block_component.rb +0 -21
- data/lib/cubit_components/engine.rb +0 -14
- data/lib/cubit_components/inline_component.rb +0 -19
- data/lib/cubit_components/page_block_component.rb +0 -37
- data/lib/cubit_components/previews/bleed_component_preview.rb +0 -13
- data/lib/cubit_components/previews/box_component_preview.rb +0 -12
- data/lib/cubit_components/previews/columns_component_preview.rb +0 -20
- data/lib/cubit_components/previews/components_index.rb +0 -28
- data/lib/cubit_components/previews/content_block_component_preview.rb +0 -13
- data/lib/cubit_components/previews/inline_component_preview.rb +0 -25
- data/lib/cubit_components/previews/page_block_component_preview.rb +0 -13
- data/lib/cubit_components/previews/page_component_preview.rb +0 -17
- data/lib/cubit_components/previews/preview_helper.rb +0 -15
- data/lib/cubit_components/previews/spread_component_preview.rb +0 -46
- data/lib/cubit_components/previews/stack_component_preview.rb +0 -22
- data/lib/cubit_components/previews/tiles_component_preview.rb +0 -20
- data/lib/cubit_components/tailwind_generated_classes_chat.txt +0 -127
- data/lib/cubit_components/tiles_component.rb +0 -43
- data/lib/cubit_components/vattr_validator.rb +0 -53
- data/lib/generators/cubit/install/install_generator.rb +0 -63
- data/lib/tasks/cubit_components_tasks.rake +0 -4
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
class StackComponentPreview < ViewComponent::Preview
|
|
4
|
-
# Shows default classes (gap-0 text-left)
|
|
5
|
-
def default
|
|
6
|
-
render(CubitComponents::StackComponent.new) do
|
|
7
|
-
tag.div("Item 1", class: "border") +
|
|
8
|
-
tag.div("Item 2", class: "border") +
|
|
9
|
-
tag.div("Item 3", class: "border")
|
|
10
|
-
end
|
|
11
|
-
end
|
|
12
|
-
|
|
13
|
-
# gap-medium
|
|
14
|
-
# Overrides gap utility
|
|
15
|
-
def custom_gap
|
|
16
|
-
render(CubitComponents::StackComponent.new(vattrs: %w[gap-medium])) do
|
|
17
|
-
tag.div("Medium gap", class: "border") +
|
|
18
|
-
tag.div("Medium gap", class: "border") +
|
|
19
|
-
tag.div("Medium gap", class: "border")
|
|
20
|
-
end
|
|
21
|
-
end
|
|
22
|
-
end
|
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
class TilesComponentPreview < ViewComponent::Preview
|
|
2
|
-
# Default preview: renders three simple tiles.
|
|
3
|
-
def default
|
|
4
|
-
render(CubitComponents::TilesComponent.new(vattrs: ["grid-cols-5"])) do
|
|
5
|
-
tag.div("Tile 1", class: "border p-2") +
|
|
6
|
-
tag.div("Tile 2", class: "border p-2") +
|
|
7
|
-
tag.div("Tile 3", class: "border p-2")
|
|
8
|
-
end
|
|
9
|
-
end
|
|
10
|
-
|
|
11
|
-
# Preview with custom grid columns and gap overrides.
|
|
12
|
-
def custom_grid_and_gap
|
|
13
|
-
render(CubitComponents::TilesComponent.new(vattrs: ["md:grid-cols-3", "gap-4"])) do
|
|
14
|
-
tag.div("Tile 1", class: "border p-2") +
|
|
15
|
-
tag.div("Tile 2", class: "border p-2") +
|
|
16
|
-
tag.div("Tile 3", class: "border p-2") +
|
|
17
|
-
tag.div("Tile 4", class: "border p-2")
|
|
18
|
-
end
|
|
19
|
-
end
|
|
20
|
-
end
|
|
@@ -1,127 +0,0 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
Well, the thing I didn't mention is that this is a Rails engine/gem, and the host app can define other custom breakpoints and I need to have tailwind capture those too. I don't think any of the solutions you mentioned can work with that. Correct me if I'm wrong.
|
|
4
|
-
|
|
5
|
-
You're absolutely right! Since this is a Rails engine/gem where the host app can define arbitrary custom breakpoints, none of my previous solutions would work. This is a tricky problem because Tailwind needs to know about classes at build time, but you don't know what breakpoints the host app will define.
|
|
6
|
-
|
|
7
|
-
Here are some approaches that could work:
|
|
8
|
-
|
|
9
|
-
## Solution 1: Host App Responsibility (Recommended)
|
|
10
|
-
|
|
11
|
-
Document that host apps need to safelist the dynamic classes themselves:
|
|
12
|
-
|
|
13
|
-
```ruby
|
|
14
|
-
# In your gem's documentation/README
|
|
15
|
-
#
|
|
16
|
-
# If you use custom breakpoints with CubitComponents::ColumnsComponent,
|
|
17
|
-
# add them to your tailwind.config.js safelist:
|
|
18
|
-
#
|
|
19
|
-
# safelist: [
|
|
20
|
-
# { pattern: /^[a-z]+:flex-row$/ },
|
|
21
|
-
# // or explicitly:
|
|
22
|
-
# 'custom-breakpoint:flex-row',
|
|
23
|
-
# 'another-breakpoint:flex-row'
|
|
24
|
-
# ]
|
|
25
|
-
```
|
|
26
|
-
|
|
27
|
-
## Solution 2: Configuration Hook
|
|
28
|
-
|
|
29
|
-
Provide a configuration option in your engine where host apps can register their breakpoints:
|
|
30
|
-
|
|
31
|
-
```ruby
|
|
32
|
-
# In your engine
|
|
33
|
-
module CubitComponents
|
|
34
|
-
class << self
|
|
35
|
-
attr_accessor :breakpoints
|
|
36
|
-
|
|
37
|
-
def configure
|
|
38
|
-
yield self
|
|
39
|
-
end
|
|
40
|
-
end
|
|
41
|
-
|
|
42
|
-
self.breakpoints = %w[sm md lg xl 2xl]
|
|
43
|
-
end
|
|
44
|
-
|
|
45
|
-
# Host app would do:
|
|
46
|
-
CubitComponents.configure do |config|
|
|
47
|
-
config.breakpoints = %w[sm md lg xl 2xl tablet desktop custom]
|
|
48
|
-
end
|
|
49
|
-
```
|
|
50
|
-
|
|
51
|
-
Then provide a rake task or generator that outputs the necessary Tailwind config:
|
|
52
|
-
|
|
53
|
-
```ruby
|
|
54
|
-
# lib/tasks/cubit_components_tasks.rake
|
|
55
|
-
namespace :cubit_components do
|
|
56
|
-
desc "Generate Tailwind safelist for CubitComponents"
|
|
57
|
-
task :tailwind_safelist => :environment do
|
|
58
|
-
breakpoints = CubitComponents.breakpoints
|
|
59
|
-
safelist = breakpoints.map { |bp| "#{bp}:flex-row" }
|
|
60
|
-
|
|
61
|
-
puts "Add this to your tailwind.config.js safelist:"
|
|
62
|
-
puts safelist.to_json
|
|
63
|
-
end
|
|
64
|
-
end
|
|
65
|
-
```
|
|
66
|
-
|
|
67
|
-
## Solution 3: Always Use Style Attribute
|
|
68
|
-
|
|
69
|
-
For truly dynamic values, you might need to bypass Tailwind classes entirely:
|
|
70
|
-
|
|
71
|
-
```ruby
|
|
72
|
-
private
|
|
73
|
-
|
|
74
|
-
def build_layout_classes(user)
|
|
75
|
-
base = %w[flex]
|
|
76
|
-
base << if @collapse_below && @reverse
|
|
77
|
-
"flex-col-reverse"
|
|
78
|
-
elsif @collapse_below
|
|
79
|
-
"flex-col"
|
|
80
|
-
else
|
|
81
|
-
"flex-row"
|
|
82
|
-
end
|
|
83
|
-
|
|
84
|
-
# Store the breakpoint for later use in style attribute
|
|
85
|
-
@responsive_style = @collapse_below
|
|
86
|
-
|
|
87
|
-
(base + user.to_s.split).join(" ")
|
|
88
|
-
end
|
|
89
|
-
|
|
90
|
-
# Then in your component's template, use a media query
|
|
91
|
-
# This would require passing the actual breakpoint value (e.g., "768px")
|
|
92
|
-
```
|
|
93
|
-
|
|
94
|
-
## Solution 4: JIT Arbitrary Value Support
|
|
95
|
-
|
|
96
|
-
If the host app uses Tailwind JIT mode, you could potentially use arbitrary values, but this still requires the host app to configure their breakpoints properly.
|
|
97
|
-
|
|
98
|
-
## Recommendation
|
|
99
|
-
|
|
100
|
-
I'd recommend **Solution 1** - making it the host app's responsibility to safelist the classes they need. This is the most common pattern for UI component libraries. You could make it easier by:
|
|
101
|
-
|
|
102
|
-
1. Providing clear documentation
|
|
103
|
-
2. Offering a generator that creates a partial Tailwind config
|
|
104
|
-
3. Providing common patterns they can use
|
|
105
|
-
|
|
106
|
-
Example generator:
|
|
107
|
-
```ruby
|
|
108
|
-
# lib/generators/cubit_components/tailwind_generator.rb
|
|
109
|
-
module CubitComponents
|
|
110
|
-
class TailwindGenerator < Rails::Generators::Base
|
|
111
|
-
def create_safelist_config
|
|
112
|
-
create_file "config/cubit_components_tailwind.js", <<~JS
|
|
113
|
-
// Add this to your tailwind.config.js safelist array
|
|
114
|
-
module.exports = {
|
|
115
|
-
// Safelist pattern for all breakpoint:flex-row combinations
|
|
116
|
-
pattern: /^[a-z0-9]+:flex-row$/,
|
|
117
|
-
|
|
118
|
-
// Or if you prefer explicit listing:
|
|
119
|
-
// 'your-custom-breakpoint:flex-row',
|
|
120
|
-
}
|
|
121
|
-
JS
|
|
122
|
-
end
|
|
123
|
-
end
|
|
124
|
-
end
|
|
125
|
-
```
|
|
126
|
-
|
|
127
|
-
This way, you're being transparent about the requirement while giving host apps full control over their Tailwind configuration.
|
|
@@ -1,43 +0,0 @@
|
|
|
1
|
-
module CubitComponents
|
|
2
|
-
class TilesComponent < BaseComponent
|
|
3
|
-
# Allowed vattrs for grid columns and gap utilities.
|
|
4
|
-
VALID_VATTRS = Set.new(
|
|
5
|
-
begin
|
|
6
|
-
valid = []
|
|
7
|
-
breakpoints = ["", "sm:", "md:", "lg:", "xl:"]
|
|
8
|
-
cols = %w[none 1 2 3 4 5]
|
|
9
|
-
breakpoints.each do |bp|
|
|
10
|
-
cols.each { |col| valid << "#{bp}grid-cols-#{col}" }
|
|
11
|
-
end
|
|
12
|
-
gap_values = %w[0 1 2 3 4 5]
|
|
13
|
-
gap_values.each { |g| valid << "gap-#{g}" }
|
|
14
|
-
valid
|
|
15
|
-
end
|
|
16
|
-
).freeze
|
|
17
|
-
|
|
18
|
-
DEFAULT_VATTRS = %w[grid-cols-1 gap-0].freeze
|
|
19
|
-
|
|
20
|
-
def initialize(element: "div", classes: "", vattrs: [])
|
|
21
|
-
# Merge defaults (grid cols and gap) with any provided overrides.
|
|
22
|
-
vattrs = merge_default_vattrs(Array(vattrs))
|
|
23
|
-
# Ensure grid display is always present.
|
|
24
|
-
classes = [classes, "grid"].join(" ").strip
|
|
25
|
-
super
|
|
26
|
-
end
|
|
27
|
-
|
|
28
|
-
private
|
|
29
|
-
|
|
30
|
-
def merge_default_vattrs(custom)
|
|
31
|
-
result = DEFAULT_VATTRS.dup
|
|
32
|
-
custom.each do |attr|
|
|
33
|
-
if attr.start_with?("grid-cols-")
|
|
34
|
-
result.reject! { |v| v.start_with?("grid-cols-") }
|
|
35
|
-
elsif attr.start_with?("gap-")
|
|
36
|
-
result.reject! { |v| v.start_with?("gap-") }
|
|
37
|
-
end
|
|
38
|
-
result << attr
|
|
39
|
-
end
|
|
40
|
-
result
|
|
41
|
-
end
|
|
42
|
-
end
|
|
43
|
-
end
|
|
@@ -1,53 +0,0 @@
|
|
|
1
|
-
module CubitComponents
|
|
2
|
-
module VattrValidator
|
|
3
|
-
extend ActiveSupport::Concern
|
|
4
|
-
|
|
5
|
-
class InvalidVattrError < ArgumentError; end
|
|
6
|
-
|
|
7
|
-
private
|
|
8
|
-
|
|
9
|
-
def validate_vattrs(vattrs, allowed_vattrs, component_name: self.class.name)
|
|
10
|
-
return if Rails.env.production?
|
|
11
|
-
|
|
12
|
-
invalid_vattrs = Array(vattrs) - Array(allowed_vattrs)
|
|
13
|
-
return if invalid_vattrs.empty?
|
|
14
|
-
|
|
15
|
-
case CubitComponents.configuration.invalid_vattr_behavior
|
|
16
|
-
when :raise
|
|
17
|
-
handle_invalid_vattrs_with_exception(invalid_vattrs, allowed_vattrs, component_name)
|
|
18
|
-
when :warn
|
|
19
|
-
handle_invalid_vattrs_with_warning(invalid_vattrs, allowed_vattrs, component_name)
|
|
20
|
-
when :silent
|
|
21
|
-
# Do nothing
|
|
22
|
-
end
|
|
23
|
-
end
|
|
24
|
-
|
|
25
|
-
def handle_invalid_vattrs_with_exception(invalid_vattrs, allowed_vattrs, component_name)
|
|
26
|
-
message = build_error_message(invalid_vattrs, allowed_vattrs, component_name)
|
|
27
|
-
raise InvalidVattrError, message
|
|
28
|
-
end
|
|
29
|
-
|
|
30
|
-
def handle_invalid_vattrs_with_warning(invalid_vattrs, allowed_vattrs, component_name)
|
|
31
|
-
message = build_error_message(invalid_vattrs, allowed_vattrs, component_name)
|
|
32
|
-
|
|
33
|
-
# Use uplevel to show the warning at the call site
|
|
34
|
-
Kernel.warn("\n#{message}", uplevel: 3)
|
|
35
|
-
|
|
36
|
-
# Also log with color if Rails logger is available
|
|
37
|
-
if defined?(Rails.logger) && Rails.logger
|
|
38
|
-
Rails.logger.warn("\e[33m#{message}\e[0m")
|
|
39
|
-
end
|
|
40
|
-
end
|
|
41
|
-
|
|
42
|
-
def build_error_message(invalid_vattrs, allowed_vattrs, component_name)
|
|
43
|
-
<<~MESSAGE
|
|
44
|
-
⚠️ [CubitComponents] Invalid vattrs for #{component_name}:
|
|
45
|
-
Invalid: #{invalid_vattrs.join(", ")}
|
|
46
|
-
|
|
47
|
-
Allowed vattrs: #{allowed_vattrs.join(", ")}
|
|
48
|
-
|
|
49
|
-
These vattrs will have no effect on the component.
|
|
50
|
-
MESSAGE
|
|
51
|
-
end
|
|
52
|
-
end
|
|
53
|
-
end
|
|
@@ -1,63 +0,0 @@
|
|
|
1
|
-
require "rails/generators" if defined?(Rails::Generators)
|
|
2
|
-
|
|
3
|
-
module Cubit
|
|
4
|
-
class InstallGenerator < Rails::Generators::Base
|
|
5
|
-
source_root File.expand_path("../templates", __FILE__)
|
|
6
|
-
|
|
7
|
-
def install
|
|
8
|
-
say "Installing Cubit Components...", :green
|
|
9
|
-
|
|
10
|
-
add_tailwind_import
|
|
11
|
-
verify_installation
|
|
12
|
-
end
|
|
13
|
-
|
|
14
|
-
private
|
|
15
|
-
|
|
16
|
-
def add_tailwind_import
|
|
17
|
-
target_file = "app/assets/tailwind/application.css"
|
|
18
|
-
|
|
19
|
-
if !File.exist?(target_file)
|
|
20
|
-
say "Could not find Tailwind CSS file to import into. Please manually add:", :red
|
|
21
|
-
say '@import "../builds/tailwind/cubit_components.css";', :yellow
|
|
22
|
-
say <<~TW_VERSION_WARNING, :red
|
|
23
|
-
⚠️ Warning: Tailwind CSS file not found at #{target_file}.
|
|
24
|
-
Please ensure you have Tailwind CSS version 4.0 or higher installed and configured correctly and that you are using a CSS config file rather than `tailwind.config.js`.
|
|
25
|
-
TW_VERSION_WARNING
|
|
26
|
-
return
|
|
27
|
-
end
|
|
28
|
-
|
|
29
|
-
content = File.read(target_file)
|
|
30
|
-
import_line = '@import "../builds/tailwind/cubit_components.css";'
|
|
31
|
-
|
|
32
|
-
if content.include?(import_line)
|
|
33
|
-
say "CubitComponents is already imported in #{target_file}", :yellow
|
|
34
|
-
return
|
|
35
|
-
end
|
|
36
|
-
|
|
37
|
-
if content.include?('@import "tailwindcss";')
|
|
38
|
-
inject_into_file target_file, after: '@import "tailwindcss";' do
|
|
39
|
-
"\n#{import_line}"
|
|
40
|
-
end
|
|
41
|
-
else
|
|
42
|
-
append_to_file target_file do
|
|
43
|
-
"\n#{import_line}"
|
|
44
|
-
end
|
|
45
|
-
end
|
|
46
|
-
|
|
47
|
-
say "Added CubitComponents import to #{target_file}", :green
|
|
48
|
-
end
|
|
49
|
-
|
|
50
|
-
def verify_installation
|
|
51
|
-
say "\nVerifying installation...", :blue
|
|
52
|
-
|
|
53
|
-
# Check if any Tailwind file contains our import
|
|
54
|
-
tailwind_files = Dir.glob("app/assets/{stylesheets,tailwind}/*.css")
|
|
55
|
-
unless tailwind_files.any? { |f| File.read(f).include?("cubit_components") }
|
|
56
|
-
say "⚠️ Warning: Cubit Components import not found in any CSS files", :red
|
|
57
|
-
say "Please manually add @import \"../builds/tailwind/cubit_components.css\"; to your main CSS file", :yellow
|
|
58
|
-
end
|
|
59
|
-
|
|
60
|
-
say "✅ Verification complete", :green
|
|
61
|
-
end
|
|
62
|
-
end
|
|
63
|
-
end
|