tailwindcss-rb 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,93 @@
1
+ require 'active_support/core_ext/object/blank'
2
+ require 'tailwindcss/helpers'
3
+
4
+ module Tailwindcss
5
+ module Compiler
6
+ class HashArgsExtractor
7
+ def call(ast:)
8
+ extract_hash_arguments_from_ast_nodes(ast)
9
+ end
10
+
11
+ private
12
+
13
+ def extract_hash_arguments_from_ast_nodes(node)
14
+ hash_args = []
15
+ return unless node.is_a?(Parser::AST::Node)
16
+
17
+ if node.type == :send
18
+ hash_args += extract_hashes(node).flatten(10)
19
+ end
20
+
21
+ node.children.each do |child|
22
+ next unless child.is_a?(Parser::AST::Node)
23
+
24
+ hash_args += extract_hash_arguments_from_ast_nodes(child)
25
+ end
26
+
27
+ hash_args.flatten.compact
28
+ end
29
+
30
+ def extract_hashes(node)
31
+ scan_for_hash_children(node).each_with_object([]) { |hash_node, acc| extract_value(hash_node, acc) }.compact
32
+ end
33
+
34
+ def scan_for_hash_children(node)
35
+ node.children[2..].select { |child| child.type == :hash }
36
+ end
37
+
38
+ def extract_value(node, acc)
39
+ node.children.select { |n| n.type == :pair }.each do |key_value_node|
40
+ key_node = key_value_node.children.first
41
+ value_node = key_value_node.children.last
42
+ value = pair_node_value(key_node, value_node)
43
+
44
+ acc << value if value.present?
45
+ end
46
+ end
47
+
48
+ def pair_node_value(key_node, value_node)
49
+ key = source_code(key_node)
50
+ case value_node.type
51
+ when :hash
52
+ hashes = []
53
+ extract_value(value_node, hashes)
54
+ hashes.flatten.map { |h| { key.to_sym => h } }
55
+ when :int, :str, :sym, :float
56
+ { key.to_sym => node_text(value_node) }
57
+ when :true
58
+ { key.to_sym => true }
59
+ when :false
60
+ { key.to_sym => false }
61
+ else
62
+ extract_color_scheme_calls(key_node, value_node)
63
+ end
64
+ end
65
+
66
+ def extract_color_scheme_calls(key_node, value_node)
67
+ value = source_code(value_node)
68
+ return unless value.include?('color_scheme_token') || value.include?('color_token')
69
+
70
+ weight_node = value_node.children[3]
71
+ weight = weight_node ? eval(source_code(weight_node)) : 500
72
+
73
+ if value.include?('color_scheme_token')
74
+ color_scheme_token = eval(source_code(value_node.children[2]))
75
+ color = Tailwindcss::Helpers.color_scheme_token(color_scheme_token, weight)
76
+ elsif value.include?('color_token')
77
+ color_token = eval(source_code(value_node.children[2]))
78
+ color = Tailwindcss::Helpers.color_token(color_token, weight)
79
+ end
80
+
81
+ { source_code(key_node).to_sym => color }
82
+ end
83
+
84
+ def node_text(node)
85
+ source_code(node).delete(':').delete('\'').to_s
86
+ end
87
+
88
+ def source_code(node)
89
+ node.location.expression.source
90
+ end
91
+ end
92
+ end
93
+ end
@@ -0,0 +1,48 @@
1
+ require "fileutils"
2
+
3
+ module Tailwindcss
4
+ module Compiler
5
+ class Output
6
+ def add_entry(file_path:, classes:)
7
+ file_path = absolute_path(file_path)
8
+ return if classes.blank?
9
+
10
+ path = output_file_path(file_path:)
11
+ folder = create_output_folder(file_path: path)
12
+
13
+ path += ".classes"
14
+ File.open(path, "wb") do |file|
15
+ file << classes.join("\n")
16
+ end
17
+ File.delete(path) if File.empty?(path)
18
+ end
19
+
20
+ def compile_classes_dir
21
+ absolute_path(Tailwindcss.config.compiler.compile_classes_dir.call)
22
+ end
23
+
24
+ def create_output_folder(file_path:)
25
+ dir_name = File.dirname(file_path)
26
+ FileUtils.mkdir_p(dir_name)
27
+ end
28
+
29
+ def output_file_path(file_path:)
30
+ content.each do |folder|
31
+ if file_path.start_with?(folder)
32
+ return File.join(compile_classes_dir, file_path.delete_prefix(folder.to_s))
33
+ end
34
+ end
35
+
36
+ return nil
37
+ end
38
+
39
+ def content
40
+ Tailwindcss.config.content.call.map { |path| absolute_path(path) }
41
+ end
42
+
43
+ def absolute_path(path)
44
+ File.expand_path(path)
45
+ end
46
+ end
47
+ end
48
+ end
@@ -0,0 +1,64 @@
1
+
2
+ require "listen"
3
+ require "tailwindcss"
4
+ require "tailwindcss/compiler/file_classes_extractor"
5
+ require "tailwindcss/compiler/output"
6
+ require "tailwindcss/compiler/connection" if defined?(ActionCable)
7
+ require "tailwindcss/compiler/channel" if defined?(ActionCable)
8
+
9
+ module Tailwindcss
10
+ module Compiler
11
+ class Runner
12
+ def initialize(watch: nil)
13
+ @watch = watch
14
+ end
15
+
16
+ def call # rubocop:disable Metrics/AbcSize, Metrics/MethodLength
17
+ output = Output.new
18
+ file_classes_extractor = FileClassesExtractor.new
19
+
20
+ content.each do |location|
21
+ if watch || (watch.nil? && Tailwindcss.config.watch_content)
22
+ listener = Listen.to(File.dirname(location.to_s), only: /\.(rb|erb)$/) do |modified, added, removed|
23
+ Tailwindcss.logger.info "Recompiling Tailwindcss..."
24
+ Tailwindcss.logger.info "Modified: #{modified}"
25
+ Tailwindcss.logger.info "Added: #{added}"
26
+ Tailwindcss.logger.info "Removed: #{removed}"
27
+ (modified + added + removed).compact.each do |file_path|
28
+ next unless File.file?(file_path)
29
+
30
+ classes = file_classes_extractor.call(file_path:)
31
+ next unless classes.present?
32
+
33
+ output.add_entry(file_path:, classes:)
34
+ end
35
+
36
+ Tailwindcss.compile_css!
37
+ end
38
+
39
+ listener.start
40
+ end
41
+
42
+ Dir.glob("#{location}/**/*").each do |file_path|
43
+ next unless File.file?(file_path)
44
+
45
+ classes = file_classes_extractor.call(file_path:)
46
+ next unless classes.present?
47
+
48
+ output.add_entry(file_path:, classes:)
49
+ end
50
+ end
51
+
52
+ Tailwindcss.compile_css!
53
+ end
54
+
55
+ private
56
+
57
+ attr_reader :watch
58
+
59
+ def content
60
+ Tailwindcss.config.content.respond_to?(:call) ? Tailwindcss.config.content.call : Tailwindcss.config.content
61
+ end
62
+ end
63
+ end
64
+ end
@@ -0,0 +1,322 @@
1
+ module Tailwindcss
2
+ module Constants
3
+ COLOR_WEIGHTS = ([nil] + %i[50 100 200 300 400 500 600 700 800 900]).freeze
4
+ BREAKPOINTS = %i[xs sm md lg xl 2xl].freeze
5
+ PSEUDO_SELECTORS = %i[hover focus active visited disabled first last first_of_type last_of_type odd even group_hover].freeze
6
+ PSEUDO_ELEMENTS = %i[before after file first_letter first_line selection backdrop marker].freeze
7
+
8
+ ALIGN_CONTENT = %i[normal center start end between around evenly baseline stretch].freeze
9
+ ALIGN_ITEMS = %i[start end center baseline stretch].freeze
10
+ BACKFACE_VISIBILITY = %i[visible hidden].freeze
11
+ BACKGROUND_ATTACHMENT = %i[fixed local scroll].freeze
12
+ BACKGROUND_BLEND_MODE = %i[normal multiply screen overlay darken lighten color-dodge color-burn hard-light
13
+ soft-light difference exclusion hue saturation color luminosity].freeze
14
+ BACKGROUND_CLIP = %i[border padding content].freeze
15
+ BACKGROUND_IMAGE = %i[none gradient-to-t gradient-to-tr gradient-to-r gradient-to-br gradient-to-b gradient-to-bl
16
+ gradient-to-l gradient-to-tl].freeze
17
+ BACKGROUND_ORIGIN = %i[border padding content].freeze
18
+ BACKGROUND_POSITION = %i[bottom center left left-bottom left-top right right-bottom right-top
19
+ top].freeze
20
+ BACKGROUND_REPEAT = %i[repeat repeat-x repeat-y no-repeat round space].freeze
21
+ BORDER_RADIUSES = %i[none sm md lg full].freeze
22
+ BACKGROUND_SIZE = %i[auto cover contain].freeze
23
+ BORDER_COLLAPSE = %i[collapse separate].freeze
24
+ BORDER_RADIUS = %i[none sm true md lg xl 2xl 3xl full] + [true].freeze
25
+ CONTENT = %i[none].freeze
26
+ SPACING = %i[0 px 0.5 1 1.5 2 2.5 3 3.5 4 5 6 7 8 9 10 11 12 14 16 20 24 28 32 36 40 44 48 52 56 60 64 72
27
+ 80 96 auto].freeze
28
+ BORDER_STYLE = %i[solid dashed dotted double none].freeze
29
+ BORDER = [true, false].freeze
30
+ BORDER_WIDTH = %i[0 1 2 4 8].freeze
31
+ BOX_DECORATION_BREAK = %i[slice clone].freeze
32
+ BOX_SHADOW = (%i[sm md lg xl 2xl inner none] + [true]).freeze
33
+ BOX_SIZING = %i[border content].freeze
34
+ CAPTION_SIDE = %i[top bottom].freeze
35
+ CLEAR = %i[left right both none].freeze
36
+ COLORS = %i[transparent current inherit black white neutral zync stone gray red amber yellow lime green blue indigo
37
+ violet purple pink slate emerald fuchsia rose cyan teal sky].freeze
38
+ COLOR_SCHEME = {
39
+ primary: :purple,
40
+ secondary: :indigo,
41
+ success: :emerald,
42
+ danger: :rose,
43
+ warning: :yellow,
44
+ info: :teal,
45
+ neutral: :gray,
46
+ dark: :black,
47
+ light: :white
48
+ }.freeze
49
+ COLUMNS = %i[auto 1 2 3 4 5 6 7 8 9 10 11 12 3xs 2xs xs sm md lg xl 2xl 3xl 4xl 5xl 6xl 7xl].freeze
50
+ COLUMN_SPAN = %i[auto 1 2 3 4 5 6 7 8 9 10 11 12 all].freeze
51
+ COLUMN_START = %i[auto 1 2 3 4 5 6 7 8 9 10 11 12 13].freeze
52
+ COLUMN_END = %i[auto 1 2 3 4 5 6 7 8 9 10 11 12 13].freeze
53
+ CURSOR = %i[auto default pointer wait text move help not-allowed].freeze
54
+ DISPLAY = %i[block inline-block inline inline-table table table-caption table-cell table-column table-column-group
55
+ table-footer-group table-header-group table-row table-row-group flow-root grid inline-grid contents
56
+ list-item hidden flex inline-flex].freeze
57
+ EMPTY_CELLS = %i[show hide].freeze
58
+ FLEX_BASIS = %i[auto 0].freeze
59
+ FLEX_DIRECTION = %i[row row-reverse col col-reverse].freeze
60
+ FLEX_GROW = [0, true].freeze
61
+ FLEX_SHRINK = [0, true].freeze
62
+ FLEX_WRAP = %i[wrap nowrap wrap-reverse].freeze
63
+ FLEX = %i[1 auto initial none].freeze
64
+ FONT_FAMILY = %i[sans serif mono].freeze
65
+ FONT_SIZE = %i[xs sm base lg xl 2xl 3xl 4xl 5xl 6xl 7xl 8xl 9xl].freeze
66
+ FONT_STYLE = %i[italic non-italic].freeze
67
+ FONT_VARIANT_NUMERIC = %i[normal-nums ordinal slashed-zero lining-nums oldstyle-nums proportional-nums
68
+ tabular-nums diagonal-fractions stacked-fractions].freeze
69
+ FONT_WEIGHT = %i[hairline thin light normal medium semibold bold extrabold black].freeze
70
+ GRID_AUTO_COLUMNS = %i[auto min max fr].freeze
71
+ GRID_AUTO_FLOW = %i[row column dense row-dense column-dense].freeze
72
+ GRID_AUTO_ROWS = %i[auto min max fr].freeze
73
+ GRID_TEMPLATE_COLUMNS = %i[none 1 2 3 4 5 6 7 8 9 10 11 12].freeze
74
+ GRID_TEMPLATE_ROWS = %i[none 1 2 3 4 5 6].freeze
75
+ GROUP = [true, false].freeze
76
+ SIZES = %i[0 px 0.5 1 1.5 2 2.5 3 3.5 4 5 6 7 8 9 10 11 12 14 16 20 24 28 32 36 40 44 48 52 56 60 64 72
77
+ 80 96 auto 1/2 1/3 2/3 1/4 2/4 3/4 1/5 2/5 3/5 4/5 1/6 2/6 3/6 4/6 5/6 full screen min max fit].freeze
78
+ HYPHENS = %i[none manual auto].freeze
79
+ ISOLATION = %i[isolate auto].freeze
80
+ JUSTIFY_CONTENT = %i[start end center between around evenly].freeze
81
+ JUSTIFY_ITEMS = %i[start end center baseline stretch].freeze
82
+ JUSTIFY_SELF = %i[start end center auto stretch].freeze
83
+ LETTER_SPACING = %i[tighter tight normal wide wider widest].freeze
84
+ LINE_HEIGHT = %i[none tight snug normal relaxed loose 3 4 5 6 7 8 9 10].freeze
85
+ LIST_STYLE_IMAGE = %i[none].freeze
86
+ LIST_STYLE_POSITION = %i[inside outside].freeze
87
+ LIST_STYLE_TYPE = %i[none disc decimal].freeze
88
+ MAX_SIZE = %i[0 xs sm md lg xl 2xl 3xl 4xl 5xl 6xl 7xl full screen min max fit prose screen-sm screen-md
89
+ screen-lg screen-xl screen-2xl].freeze
90
+ MIN_SIZE = [0, :full, :min, :max, :fit].freeze
91
+ MIX_BLEND_MODE = %i[normal multiply screen overlay darken lighten color-dodge color-burn hard-light soft-light
92
+ difference exclusion hue saturation color luminosity].freeze
93
+ OBJECT_FIT = %i[contain cover fill none scale-down].freeze
94
+ OBJECT_POSITION = %i[top right bottom left center].freeze
95
+ OPACITY = %i[0 5 10 20 25 30 40 50 60 70 75 80 90 95 100].freeze
96
+ ORDER = %i[first last none 1 2 3 4 5 6 7 8 9 10 11 12].freeze
97
+ OUTLINE_STYLE = %i[dotted dashed solid double none].freeze
98
+ OUTLINE_WIDTH = %i[0 1 2 4 8].freeze
99
+ OVERFLOW = %i[auto hidden visible scroll x-hidden y-hidden x-scroll y-scroll x-auto y-auto].freeze
100
+ PLACE_ITEMS = %i[start end center stretch].freeze
101
+ PLACE_SELF = %i[start end center stretch].freeze
102
+ POINTER_EVENTS = %i[none auto].freeze
103
+ POSITION = %i[static fixed absolute relative sticky].freeze
104
+ RESIZE = %i[true false none x y].freeze
105
+ ROTATE = %i[0 1 2 3 6 12 45 90 180].map { [_1, :"-#{_1}"] }.flatten.freeze
106
+ ROW_SPAN = %i[auto 1 2 3 4 5 6 full].freeze
107
+ ROW_START = %i[auto 1 2 3 4 5 6 7].freeze
108
+ ROW_END = %i[auto 1 2 3 4 5 6 7].freeze
109
+ SCALE = %i[0 50 75 90 95 100 105 110 125 150 200].freeze
110
+ SCROLL_BEHAVIOR = %i[auto smooth].freeze
111
+ SCROLL_SNAP_ALIGN = %i[start end center none].freeze
112
+ SCROLL_SNAP_STOP = %i[always normal].freeze
113
+ SCROLL_SNAP_TYPE = %i[none mandatory proximity].freeze
114
+ TABLE_LAYOUT = %i[auto fixed].freeze
115
+ TEXT_ALIGN = %i[left center right justify start end].freeze
116
+ TEXT_DECORATION = %i[underline line-through no-underline].freeze
117
+ TEXT_DECORATION_STYLE = %i[solid double dotted dashed wavy].freeze
118
+ TEXT_DECORATION_THICKNESS = %i[auto from-font 0 1 2 4 8].freeze
119
+ TEXT_OVERFLOW = %i[ellipsis truncate].freeze
120
+ TEXT_TRANSFORM = %i[uppercase lowercase capitalize normal].freeze
121
+ TEXT_UNDERLINE_OFFSET = %i[auto 0 1 2 4 8].freeze
122
+ TRANSFORM_ORIGIN = %i[center top-right top top-left right bottom-right bottom bottom-left left].freeze
123
+ TRANSITION = %i[none all colors opacity shadow transform].freeze
124
+ TRANSLATE = %i[0 0.5 px 1 1.5 2 2.5 3 3.5 4 5 6 7 8 9 10 11 12 14 16 20 24 28 32 36 40 44 48 52 56 60 64 72 80 96 1/2 1/3 2/3 1/4 2/3 2/4 3/4 full].map { [_1, :"-#{_1}"] }.flatten.freeze
125
+ USER_SELECT = %i[none text all auto].freeze
126
+ VERTICAL_ALIGN = %i[top middle bottom baseline text-top text-bottom sub super].freeze
127
+ VISIBILITY = %i[visible invisible collapse].freeze
128
+ WHITESPACE = %i[normal nowrap pre pre-line pre-wrap break-words].freeze
129
+ WILL_CHANGE = %i[auto scroll contents opacity transform].freeze
130
+ WORD_BREAK = %i[normal words all keep].freeze
131
+ Z_INDEX = %i[0 10 20 30 40 50 auto].freeze
132
+
133
+ COLOR_WITH_WEIGHTS = proc {
134
+ COLORS.map do |color|
135
+ COLOR_WEIGHTS.map { |weight| [color, weight].compact.join("-") }
136
+ end.flatten.freeze
137
+ }
138
+
139
+ THEME = {
140
+ align_content: {values: ALIGN_CONTENT, token: "content"},
141
+ align_items: {values: ALIGN_ITEMS, token: "items", alias: :items},
142
+ backface_visibility: {values: BACKFACE_VISIBILITY, token: "backface"},
143
+ background: {values: COLOR_WITH_WEIGHTS, token: "bg", alias: :bg},
144
+ background_attachment: {values: BACKGROUND_ATTACHMENT, token: "bg"},
145
+ background_blend_mode: {values: BACKGROUND_BLEND_MODE, token: "bg"},
146
+ background_clip: {values: BACKGROUND_CLIP, token: "bg"},
147
+ background_color: {values: COLOR_WITH_WEIGHTS, token: "bg"},
148
+ background_image: {values: BACKGROUND_IMAGE, token: "bg"},
149
+ background_origin: {values: BACKGROUND_ORIGIN, token: "bg"},
150
+ background_position: {values: BACKGROUND_POSITION, token: "bg"},
151
+ background_repeat: {values: BACKGROUND_REPEAT, token: "bg"},
152
+ background_size: {values: BACKGROUND_SIZE, token: "bg"},
153
+ border_bottom_left_radius: {values: BORDER_RADIUS, token: "rounded-bl"},
154
+ border_bottom_right_radius: {values: BORDER_RADIUS, token: "rounded-br"},
155
+ border_top_left_radius: {values: BORDER_RADIUS, token: "rounded-tl"},
156
+ border_top_right_radius: {values: BORDER_RADIUS, token: "rounded-tr"},
157
+ border_top_radius: {values: BORDER_RADIUS, token: "rounded-t"},
158
+ border_bottom_radius: {values: BORDER_RADIUS, token: "rounded-b"},
159
+ border_left_radius: {values: BORDER_RADIUS, token: "rounded-l"},
160
+ border_right_radius: {values: BORDER_RADIUS, token: "rounded-r"},
161
+ border_collapse: {values: BORDER_COLLAPSE, token: "border"},
162
+ border_color: {values: COLOR_WITH_WEIGHTS, token: "border"},
163
+ border_radius: {values: BORDER_RADIUS, token: "rounded", alias: :rounded},
164
+ border_spacing: {values: SPACING, token: "border-spacing"},
165
+ border_spacing_x: {values: SPACING, token: "border-spacing-x"},
166
+ border_spacing_y: {values: SPACING, token: "border-spacing-y"},
167
+ border_style: {values: BORDER_STYLE, token: "border"},
168
+ border: {values: BORDER, token: "border"},
169
+ border_top: {values: BORDER + BORDER_WIDTH, token: "border-t"},
170
+ border_bottom: {values: BORDER + BORDER_WIDTH, token: "border-b"},
171
+ border_left: {values: BORDER + BORDER_WIDTH, token: "border-l"},
172
+ border_right: {values: BORDER + BORDER_WIDTH, token: "border-r"},
173
+ border_width: {values: BORDER_WIDTH, token: "border"},
174
+ border_y: {values: BORDER_WIDTH, token: "border-y"},
175
+ border_x: {values: BORDER_WIDTH, token: "border-x"},
176
+ border_start: {values: BORDER_WIDTH, token: "border-s"},
177
+ border_end: {values: BORDER_WIDTH, token: "border-e"},
178
+ bottom: {values: SIZES, token: "bottom"},
179
+ box_decoration_break: {values: BOX_DECORATION_BREAK, token: "box-decoration-break"},
180
+ box_shadow: {values: BOX_SHADOW, token: "shadow", alias: :shadow},
181
+ box_sizing: {values: BOX_SIZING, token: "box"},
182
+ caption_side: {values: CAPTION_SIDE, token: "caption"},
183
+ clear: {values: CLEAR, token: "clear"},
184
+ color: {values: COLOR_WITH_WEIGHTS, token: "text"},
185
+ column_gap: {values: SPACING, token: "gap"},
186
+ column_span: {values: COLUMN_SPAN, token: "col-span", alias: :col_span},
187
+ column_start: {values: COLUMN_START, token: "col-start", alias: :col_start},
188
+ column_end: {values: COLUMN_END, token: "col-end", alias: :col_end},
189
+ columns: {values: COLUMNS, token: "columns"},
190
+ content: {values: CONTENT, token: "content"},
191
+ cursor: {values: CURSOR, token: "cursor"},
192
+ display: {values: DISPLAY, token: nil, alias: :d},
193
+ empty_cells: {values: EMPTY_CELLS, token: "empty"},
194
+ end: {values: SIZES, token: "end"},
195
+ fill: {values: COLOR_WITH_WEIGHTS, token: "fill"},
196
+ flex_basis: {values: FLEX_BASIS, token: "flex"},
197
+ flex_direction: {values: FLEX_DIRECTION, token: "flex", alias: :direction},
198
+ flex_grow: {values: FLEX_GROW, token: "flex", alias: :grow},
199
+ flex_shrink: {values: FLEX_SHRINK, token: "flex", alias: :shrink},
200
+ flex_wrap: {values: FLEX_WRAP, token: "flex"},
201
+ flex: {values: FLEX, token: "flex"},
202
+ font_family: {values: FONT_FAMILY, token: "font"},
203
+ font_size: {values: FONT_SIZE, token: "text"},
204
+ font_style: {values: FONT_STYLE, token: nil},
205
+ font_variant_numeric: {values: FONT_VARIANT_NUMERIC, token: nil},
206
+ font_weight: {values: FONT_WEIGHT, token: "font"},
207
+ grid_auto_columns: {values: GRID_AUTO_COLUMNS, token: "auto-cols"},
208
+ grid_auto_flow: {values: GRID_AUTO_FLOW, token: "grid-flow"},
209
+ grid_auto_rows: {values: GRID_AUTO_ROWS, token: "auto-rows"},
210
+ group: {values: GROUP, token: "group"},
211
+ gap: {values: SPACING, token: "gap"},
212
+ gap_x: {values: SPACING, token: "gap-x"},
213
+ gap_y: {values: SPACING, token: "gap-y"},
214
+ grid_template_columns: {values: GRID_TEMPLATE_COLUMNS, token: "grid-cols", alias: :grid_cols},
215
+ grid_template_rows: {values: GRID_TEMPLATE_ROWS, token: "grid-rows"},
216
+ height: {values: SIZES, token: "h", alias: :h},
217
+ hyphens: {values: HYPHENS, token: "hyphens"},
218
+ inset: {values: SIZES, token: "inset"},
219
+ inset_x: {values: SIZES, token: "inset-x"},
220
+ inset_y: {values: SIZES, token: "inset-y"},
221
+ isolation: {values: ISOLATION, token: "isolation"},
222
+ justify_content: {values: JUSTIFY_CONTENT, token: "justify", alias: :justify},
223
+ justify_items: {values: JUSTIFY_ITEMS, token: "justify"},
224
+ justify_self: {values: JUSTIFY_SELF, token: "justify"},
225
+ left: {values: SIZES, token: "left"},
226
+ letter_spacing: {values: LETTER_SPACING, token: "tracking"},
227
+ line_height: {values: LINE_HEIGHT, token: "leading"},
228
+ list_style_image: {values: LIST_STYLE_IMAGE, token: "list-image"},
229
+ list_style_position: {values: LIST_STYLE_POSITION, token: "list"},
230
+ list_style_type: {values: LIST_STYLE_TYPE, token: "list"},
231
+ margin_bottom: {values: SPACING, token: "mb", alias: :mb},
232
+ margin_end: {values: SPACING, token: "me", alias: :me},
233
+ margin_left: {values: SPACING, token: "ml", alias: :ml},
234
+ margin_right: {values: SPACING, token: "mr", alias: :mr},
235
+ margin_start: {values: SPACING, token: "ms", alias: :ms},
236
+ margin_top: {values: SPACING, token: "mt", alias: :mt},
237
+ margin_x: {values: SPACING, token: "mx", alias: :mx},
238
+ margin_y: {values: SPACING, token: "my", alias: :my},
239
+ margin: {values: SPACING, token: "m", alias: :m},
240
+ max_height: {values: SIZES, token: "max-h", alias: :max_h},
241
+ max_width: {values: SIZES, token: "max-w", alias: :max_w},
242
+ min_height: {values: SIZES, token: "min-h", alias: :min_h},
243
+ min_width: {values: SIZES, token: "min-w", alias: :min_w},
244
+ mix_blend_mode: {values: MIX_BLEND_MODE, token: "mix-blend"},
245
+ object_fit: {values: OBJECT_FIT, token: "object"},
246
+ object_position: {values: OBJECT_POSITION, token: "object"},
247
+ opacity: {values: OPACITY, token: "opacity"},
248
+ order: {values: ORDER, token: "order"},
249
+ outline_color: {values: COLOR_WITH_WEIGHTS, token: "outline"},
250
+ outline_style: {values: OUTLINE_STYLE, token: "outline", alias: :outline},
251
+ outline_width: {values: OUTLINE_WIDTH, token: "outline"},
252
+ overflow: {values: OVERFLOW, token: "overflow"},
253
+ overflow_x: {values: OVERFLOW, token: "overflow-x"},
254
+ overflow_y: {values: OVERFLOW, token: "overflow-y"},
255
+ padding: {values: SPACING, token: "p", alias: :p},
256
+ padding_bottom: {values: SPACING, token: "pb", alias: :pb},
257
+ padding_left: {values: SPACING, token: "pl", alias: :pl},
258
+ padding_right: {values: SPACING, token: "pr", alias: :pr},
259
+ padding_top: {values: SPACING, token: "pt", alias: :pt},
260
+ padding_x: {values: SPACING, token: "px", alias: :px},
261
+ padding_y: {values: SPACING, token: "py", alias: :py},
262
+ place_items: {values: PLACE_ITEMS, token: "place"},
263
+ place_self: {values: PLACE_SELF, token: "place"},
264
+ pointer_events: {values: POINTER_EVENTS, token: "pointer"},
265
+ position: {values: POSITION, token: nil},
266
+ resize: {values: RESIZE, token: "resize"},
267
+ right: {values: SIZES, token: "right"},
268
+ rotate: {values: ROTATE, token: proc { _1.to_s.start_with?("-") ? "-rotate-#{_1.to_s[1..-1]}" : "rotate-#{_1}" }},
269
+ row_gap: {values: SPACING, token: "gap"},
270
+ row_span: {values: ROW_SPAN, token: "row-span"},
271
+ row_start: {values: ROW_START, token: "row-start"},
272
+ row_end: {values: ROW_END, token: "row-end"},
273
+ scale: {values: SCALE, token: "scale"},
274
+ scale_x: {values: SCALE, token: "scale-x"},
275
+ scale_y: {values: SCALE, token: "scale-y"},
276
+ scroll_behavior: {values: SCROLL_BEHAVIOR, token: "scroll"},
277
+ scroll_margin_bottom: {values: SPACING, token: "scroll-mb"},
278
+ scroll_margin_left: {values: SPACING, token: "scroll-ml"},
279
+ scroll_margin_right: {values: SPACING, token: "scroll-mr"},
280
+ scroll_margin_top: {values: SPACING, token: "scroll-mt"},
281
+ scroll_margin_x: {values: SPACING, token: "scroll-mx"},
282
+ scroll_margin_y: {values: SPACING, token: "scroll-my"},
283
+ scroll_margin_start: {values: SPACING, token: "scroll-ms"},
284
+ scroll_margin_end: {values: SPACING, token: "scroll-me"},
285
+ scroll_padding_bottom: {values: SPACING, token: "scroll-pb"},
286
+ scroll_padding_left: {values: SPACING, token: "scroll-pl"},
287
+ scroll_padding_right: {values: SPACING, token: "scroll-pr"},
288
+ scroll_padding_top: {values: SPACING, token: "scroll-pt"},
289
+ scroll_padding_x: {values: SPACING, token: "scroll-px"},
290
+ scroll_padding_y: {values: SPACING, token: "scroll-py"},
291
+ scroll_padding_start: {values: SPACING, token: "scroll-ps"},
292
+ scroll_padding_end: {values: SPACING, token: "scroll-pe"},
293
+ scroll_snap_align: {values: SCROLL_SNAP_ALIGN, token: "snap"},
294
+ scroll_snap_stop: {values: SCROLL_SNAP_STOP, token: "snap"},
295
+ scroll_snap_type: {values: SCROLL_SNAP_TYPE, token: "snap"},
296
+ start: {values: SIZES, token: "start"},
297
+ table_layout: {values: TABLE_LAYOUT, token: "table"},
298
+ text_align: {values: TEXT_ALIGN, token: "text"},
299
+ text_decoration_color: {values: COLOR_WITH_WEIGHTS, token: "decoration"},
300
+ text_decoration_style: {values: TEXT_DECORATION_STYLE, token: "decoration"},
301
+ text_decoration_thickness: {values: TEXT_DECORATION_THICKNESS, token: "decoration"},
302
+ text_decoration: {values: TEXT_DECORATION, token: proc { _1 }},
303
+ text_indent: {values: SPACING, token: "indent"},
304
+ text_overflow: {values: TEXT_OVERFLOW, token: proc { |v| (v == "truncate") ? "truncate" : "text-#{v}" }},
305
+ text_transform: {values: TEXT_TRANSFORM, token: nil},
306
+ text_underline_offset: {values: TEXT_UNDERLINE_OFFSET, token: "underline-offset"},
307
+ top: {values: SIZES, token: "top"},
308
+ transform_origin: {values: TRANSFORM_ORIGIN, token: "origin"},
309
+ transition: {values: TRANSITION + [true], token: "transition"},
310
+ translate_x: {values: TRANSLATE, token: proc { _1.to_s.start_with?("-") ? "-translate-#{_1.to_s[1..-1]}" : "translate-#{_1}" }},
311
+ translate_y: {values: TRANSLATE, token: proc { _1.to_s.start_with?("-") ? "-translate-y-#{_1.to_s[1..-1]}" : "translate-y-#{_1}" }},
312
+ user_select: {values: USER_SELECT, token: "select"},
313
+ vertical_align: {values: VERTICAL_ALIGN, token: "align"},
314
+ visibility: {values: VISIBILITY, token: nil},
315
+ whitespace: {values: WHITESPACE, token: "whitespace", alias: :white_space},
316
+ width: {values: SIZES, token: "w", alias: :w},
317
+ will_change: {values: WILL_CHANGE, token: "will-change"},
318
+ word_break: {values: WORD_BREAK, token: "break"},
319
+ z_index: {values: Z_INDEX, token: "z", alias: :z}
320
+ }.freeze
321
+ end
322
+ end
@@ -0,0 +1,26 @@
1
+ module Tailwindcss
2
+ module Helpers
3
+ extend self
4
+
5
+ def tailwind(**style_attributes)
6
+ Style.new(**style_attributes).to_s
7
+ end
8
+ alias tw tailwind
9
+
10
+ def ab(value)
11
+ ArbitraryValue.new(value)
12
+ end
13
+
14
+ # @param token [String] A value your Tailwindcss.theme.color_scheme keys
15
+ # @param weight [Integer] A value between 100 and 900
16
+ def color_scheme_token(token, weight = 500)
17
+ color_token(Tailwindcss.theme.color_scheme[token.to_sym], weight)
18
+ end
19
+
20
+ # @param color_token [String] A value your of any of tailwinds color tokens
21
+ # @param weight [Integer] A value between 100 and 900
22
+ def color_token(color_token, weight = 500)
23
+ "#{color_token}-#{weight}"
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,17 @@
1
+ require "tailwindcss/installers/config_file_generator"
2
+
3
+ module Tailwindcss
4
+ class Installer
5
+ def call
6
+ Installers::ConfigFileGenerator.new.call
7
+ install_packages
8
+ end
9
+
10
+ private
11
+
12
+ def install_packages
13
+ system("yarn init -y") unless File.exist?('./package.json')
14
+ system("yarn add -D tailwindcss autoprefixer postcss")
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,37 @@
1
+ require "tailwindcss"
2
+ require "json"
3
+
4
+ module Tailwindcss
5
+ module Installers
6
+ class ConfigFileGenerator
7
+ def call
8
+ File.write("./tailwind.config.js", tailwind_config_file_content)
9
+ end
10
+
11
+ private
12
+
13
+ def content
14
+ value = Tailwindcss.config.content
15
+ return value unless value.respond_to?(:call)
16
+
17
+ value.call
18
+ end
19
+
20
+ def tailwind_config_file_content
21
+ content_option = (content + ["./tmp/tailwindcss"]).map { "#{_1}/**/*" }
22
+ <<~TAILWIND_CONFIG
23
+ /** @type {import('tailwindcss').Config} */
24
+
25
+ /** this file was generated automatically, please do not modify it directly!! */
26
+ /** instead change your tailwindcss-rb config and run `bundle exec rake tailwindcss:generate_config_file` */
27
+
28
+ export default {
29
+ content: #{content_option.to_json},
30
+ prefix: '#{Tailwindcss.config.prefix}',
31
+ #{Tailwindcss.config.tailwind_config_overrides.call.map { |k, v| "#{k}: #{v}," }.join("\n")}
32
+ }
33
+ TAILWIND_CONFIG
34
+ end
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,29 @@
1
+ require "ostruct"
2
+ require "tailwindcss/style_attributes_to_list_converter"
3
+
4
+ module Tailwindcss
5
+ class Style < ::OpenStruct
6
+ def initialize(attributes = {})
7
+ super
8
+ @attributes = attributes
9
+ end
10
+
11
+ def to_a
12
+ to_string_converter.call(**@attributes)
13
+ end
14
+
15
+ def to_s
16
+ to_a.join(" ")
17
+ end
18
+
19
+ def to_html_attributes
20
+ {class: to_s}
21
+ end
22
+
23
+ private
24
+
25
+ def to_string_converter
26
+ @to_string_converter ||= StyleAttributesToListConverter.new
27
+ end
28
+ end
29
+ end