1:- module(grammar, [tailwind//1, prefixes//2]).
9:- use_module(library(apply_macros)). 10:- use_module(library(apply), [maplist/3]). 11:- use_module(library(dcg/basics), [integer//1, string_without//2]). 12:- use_module(library(dcg/high_order), [optional//2]). 13:- use_module(library(yall)). 14
15:- use_module(tw_utils). 16:- use_module(colours, [colour//1,
17 has_alpha/1,
18 colour_css/2,
19 as_transparent/2,
20 colour_with_alpha/3]).
28prefixes(Medias, States) -->
29 media_queries(Medias), state_variants(States).
30
31media_queries([Media|Medias]) -->
32 media_query(Media), ":", !,
33 media_queries(Medias).
34media_queries([]) --> [].
35
36media_query(min_width("640px")) --> "sm".
37media_query(min_width("768px")) --> "md".
38media_query(min_width("1024px")) --> "lg".
39media_query(min_width("1280px")) --> "xl".
40media_query(min_width("1536")) --> "2xl".
41
42media_query(color_scheme(light)) --> "light".
43media_query(color_scheme(dark)) --> "dark".
44
45media_query(motion("no-preference")) --> "motion-safe".
46media_query(motion("reduced")) --> "motion-reduce".
47
48state_variants([State|States]) -->
49 state_variant(State), ":", !,
50 state_variants(States).
51state_variants([]) --> [].
52
53state_variant(outer(Variant)) -->
54 "group-", one_of(["hover", "focus", "disabled", "active"],
55 GroupVariant), !,
56 { format(atom(Variant), ".group:~w", [GroupVariant]) }.
57state_variant(outer(Variant)) -->
58 "group-attr-", string_without(":", Attr), !,
59 { format(atom(Variant), ".group[~s]", [Attr]) }.
60state_variant(inner(Variant)) -->
61 one_of(
62 ["hover", "focus", "disabled", "active",
63 "focus-within", "focus-visible",
64 "any-link", "link", "visited", "target",
65 "blank", "required", "optionaly", "valid", "invalid",
66 "placeholder-shown", "checked", "read-only", "read-write",
67 68 "first-of-type", "last-of-type", "root", "empty"],
69 Variant).
70state_variant(inner("first-child")) --> "first", !.
71state_variant(inner("last-child")) --> "last", !.
72state_variant(inner("nth-child(odd)")) --> "odd", !.
73state_variant(inner("nth-child(even)")) --> "even", !.
74
75:- discontiguous tailwind//1. 76
82tailwind('flex-grow'(V)) -->
83 "flex-grow-", optional(fraction(N), num(N)),
84 { value_unit_css(N, V, _{}) }.
85tailwind('flex-grow'(1)) --> "flex-grow".
86
87tailwind('flex-shrink'(V)) -->
88 "flex-shrink-", optional(fraction(N), num(N)),
89 { value_unit_css(N, V, _{}) }.
90tailwind('flex-shrink'(1)) --> "flex-shrink".
91
92flex_basis_value(Val) --> fraction(Val).
93flex_basis_value(Val) --> percentage(Val).
94flex_basis_value(Val) --> length(Val).
95flex_basis_value(Val) --> length_unit(Val).
96flex_basis_value(Val) --> num(Val).
97flex_basis_value(full_100) --> "full".
98flex_basis_value(auto) --> "auto".
99
100tailwind('flex-basis'(N)) -->
101 "flex-basis-", flex_basis_value(Val), !,
102 { value_unit_css(Val, N, _{zero: "",
103 number: _{unit: rem,
104 value_fn: div_4},
105 fraction: _{unit: '%',
106 value_fn: mul_100}}) }.
107tailwind('flex-basis'(1)) --> "flex-basis", !.
108
109tailwind('flex'("none")) --> "flex-none", !.
110tailwind('flex'("0 1 auto")) --> "flex-initial", !.
111tailwind('flex'("1 1 auto")) --> "flex-auto", !.
112tailwind('flex'(S)) -->
113 "flex-",
114 optional(fraction(GrowN), num(GrowN)),
115 "-", optional(fraction(ShrinkN), num(ShrinkN)),
116 "-", flex_basis_value(BasisN), !,
117 { value_unit_css(GrowN, Grow, _{}),
118 value_unit_css(ShrinkN, Shrink, _{}),
119 value_unit_css(BasisN, Basis, _{zero_unit: "",
120 number: _{unit: "rem",
121 value_fn: div_4},
122 fraction: _{unit: "%",
123 value_fn: mul_100}
124 }),
125 format(string(S), "~w ~w ~w", [Grow, Shrink, Basis]) }.
126tailwind('flex'(S)) -->
127 "flex-",
128 optional(fraction(GrowN), num(GrowN)),
129 "-", flex_basis_value(ShrinkOrBasisN), !,
130 { value_unit_css(GrowN, Grow, _{}),
131 value_unit_css(ShrinkOrBasisN, ShrinkOrBasis, _{}),
132 format(string(S), "~w ~w", [Grow, ShrinkOrBasis]) }.
133tailwind('flex'(S)) -->
134 "flex-", optional(fraction(N), num(N)), !,
135 { value_unit_css(N, CssN, _{}),
136 format(string(S), "~w ~w 0%", [CssN, CssN]) }, !.
137
138tailwind('flex-direction'("row-reverse")) --> "flex-row-reverse", !.
139tailwind('flex-direction'("row")) --> "flex-row", !.
140tailwind('flex-direction'("column-reverse")) --> "flex-col-reverse", !.
141tailwind('flex-direction'("column")) --> "flex-col", !.
142
143tailwind('flex-wrap'(Wrap)) -->
144 one_of(["wrap-reverse", "wrap", "nowrap"], Wrap).
145
146tailwind(order(-9999)) --> "order-first", !.
147tailwind(order(9999)) --> "order-last", !.
148tailwind(order(0)) --> "order-none", !.
149tailwind(order(O)) -->
150 soft_optional(signus(S), { S = '+' }),
151 "order-",
152 integer(N), !,
153 { value_unit_css(integer(N), O, _{signus: S }) }.
154
156
157tailwind([position(absolute), width("1px"), height("1px"),
158 padding(0), margin("-1px"), overflow(hidden),
159 clip("rect(0,0,0,0)"), 'white-space'(nowrap),
160 'border-width'(0)]) -->
161 "sr-only", !.
162tailwind([position(static), width(auto), height(auto),
163 padding(0), margin(0), overflow(visible),
164 clip(auto), 'white-space'(normal)]) -->
165 "not-sr-only", !.
166
168
169tailwind('transition-property'(none)) --> "tranistion-none", !.
170tailwind(['transition-property'(Prop),
171 'transition-timing-function'("cubic-bezier(0.4,0,0.2.1)"),
172 'transition-duration'("150ms")]) -->
173 "transition-",
174 transition_property(Prop), !.
175tailwind(['transition-property'("background-color,border-color,color,fill,stroke,opacity,box-shadow,transform"),
176 'transition-timing-function'("cubic-bezier(0.4,0,0.2.1)"),
177 'transition-duration'("150ms")]) -->
178 "transition".
179
180transition_property("all") --> "all".
181transition_property("background-color,border-color,color,fill-stroke") -->
182 "colors".
183transition_property("opacity") --> "opacity".
184transition_property("box-shadow") --> "shadow".
185transition_property("transform") --> "transform".
186
187tailwind('transition-duration'(Dur)) -->
188 "duration-", optional(time(N), num(N)), !,
189 { value_unit_css(N, Dur, _{zero_unit: s, number: _{unit: ms}})}.
190
191tailwind('transition-timing-function'(Fun)) -->
192 "ease-", transition_timing_fn(Fun), !.
193
194transition_timing_fn("linear") --> "linear".
195transition_timing_fn("cubic-bezier(0.4,0,0.2,1)") --> "in-out".
196transition_timing_fn("cubic-bezier(0.4,0,1,1)") --> "in".
197transition_timing_fn("cubic-bezier(0,0,0.2,1)") --> "out".
198
199tailwind('transition-delay'(Delay)) -->
200 "delay-", optional(time(N), num(N)), !,
201 { value_unit_css(N, Delay, _{zero_unit: s, number: _{unit: ms}}) }.
202
203tailwind('animation'("none")) --> "animate-none", !.
204tailwind(['animation'("spin 1s linear infinite"),
205 '@keyframes'(spin,
206 [from(transform("rotate(0)")),
207 to(transform("rotate(360deg)"))])]) -->
208 "animate-spin", !.
209tailwind(['animation'("ping 1s cubic-bezier(0,0,0.2,1) infinite"),
210 '@keyframes'(ping,
211 ['75%, 100%'(transform("scale(2)"),
212 opacity(0))])]) -->
213 "animate-ping", !.
214tailwind(['animation'("pulse 2s cubic-bezier(0.4,0,0.6,1) infinite"),
215 '@keyframes'(pulse,
216 ['0%, 100%'(opacity(0)),
217 '50%'(opacity(0.5))])]) -->
218 "animate-pulse", !.
219tailwind(['animation'("bounce 1s infinite"),
220 '@keyframes'(bounce,
221 ['0%, 100%'(transform("translateY(-25%)"),
222 'animation-timing-function'("cubic-bezier(0.8,0,1,1)")),
223 '50%'(transform("translateY(0)"),
224 'animation-timing-function'("cubic-bezier(0,0,0.2,1)"))])]) -->
225 "animate-bounce", !.
226
228
229tailwind('background-attachment'(Attachment)) -->
230 "bg-", one_of(["fixed", "local", "scroll"],
231 Attachment), !.
232
233tailwind('background-clip'("text")) --> "bg-clip-text", !.
234tailwind('background-clip'(Box)) -->
235 "bg-clip-",
236 one_of(["border", "padding", "content"], Type), !,
237 { format(string(Box), "~w-box", [Type]) }.
238
239colour_bg(special(S), S) :- !.
240colour_bg(Colour, CssColour) :-
241 ( has_alpha(Colour)
242 -> Colour_ = Colour
243 ; colour_with_alpha(Colour, "var(--pl-bg-opacity, 1)", Colour_) ),
244 colour_css(Colour_, CssColour).
245
246tailwind('background-color'(CssColour)) -->
247 "bg-", colour(Colour), !,
248 { colour_bg(Colour, CssColour) }.
249
250tailwind('--pl-bg-opacity'(Opacity)) -->
251 "bg-opacity-", num(N), !,
252 { value_unit_css(N, Opacity, _{value_fn: div_100}) }.
253
254tailwind('background-position'("right top")) --> "bg-right-top".
255tailwind('background-position'("left top")) --> "bg-left-top".
256tailwind('background-position'("right bottom")) --> "bg-right-bottom".
257tailwind('background-position'("left bottom")) --> "bg-left-bottom".
258tailwind('background-position'(Pos)) -->
259 "bg-", one_of(["top", "center", "bottom", "left", "right"], Pos).
260
261background_size_length(Len) -->
262 alternates([auto(Len),
263 length(Len), length_unit(Len),
264 fraction(Len), percentage(Len),
265 num(Len)]).
266
267tailwind('background-size'(Size)) -->
268 "bg-", one_of(["auto", "cover", "contain"], Size), !.
269tailwind('background-size'(Size)) -->
270 "bg-size-", background_size_length(Width),
271 "-", background_size_length(Height), !,
272 { Opts = _{zero_unit: "",
273 number: _{unit: rem, value_fn: div_4},
274 fraction: _{unit: "%", value_fn: mul_100}},
275 value_unit_css(Width, WidthCss, Opts),
276 value_unit_css(Height, HeightCss, Opts),
277 format(string(Size), "~w ~w", [WidthCss, HeightCss]) }.
278
279gradient_direction("top right") --> "tr".
280gradient_direction("top left") --> "tl".
281gradient_direction("top") --> "t".
282gradient_direction("left") --> "l".
283gradient_direction("right") --> "r".
284gradient_direction("bottom right") --> "br".
285gradient_direction("bottom left") --> "bl".
286gradient_direction("bottom") --> "b".
287
288tailwind('background-image'("none")) --> "bg-none", !.
289tailwind('background-image'(Grad)) -->
290 "bg-gradient-to-", gradient_direction(Dir), !,
291 { format(string(Grad), "linear-gradient(to ~w, var(--pl-gradient-stops))",
292 [Dir]) }.
293
294tailwind(['--pl-gradient-from'(ColourCss),
295 '--pl-gradient-stops'(Stops)]) -->
296 "from-", colour(Colour), !,
297 { colour_css(Colour, ColourCss),
298 as_transparent(Colour, TranspColour), colour_css(TranspColour, TranspColourCss),
299 format(string(Stops),
300 "var(--pl-gradient-from), var(--pl-gradient-to, ~w)",
301 [TranspColourCss]) }.
302
303tailwind('--pl-gradient-to'(ColourCss)) -->
304 "to-", colour(Colour), !,
305 { colour_css(Colour, ColourCss) }.
306
307tailwind('--pl-gradient-stops'(Stops)) -->
308 "via-", colour(Colour), !,
309 { as_transparent(Colour, ColourTransp),
310 colour_css(Colour, ColourCss),
311 colour_css(ColourTransp, ColourTranspCss),
312 format(string(Stops),
313 "var(--pl-gradient-from),~w,var(--pl-gradient-to,~w)",
314 [ColourCss, ColourTranspCss]) }.
315
317
318border_radius_pos(Pos) -->
319 "-", one_of(["tl", "tr", "t",
320 "bl", "br", "b",
321 "r", "l"],
322 Pos_),
323 { border_radius_pos_dirs(Pos_, Pos) }.
324
325border_radius_pos_dirs(t, ["top-left", "top-right"]).
326border_radius_pos_dirs(r, ["top-right", "bottom-right"]).
327border_radius_pos_dirs(b, ["bottom-right", "bottom-left"]).
328border_radius_pos_dirs(l, ["bottom-left", "top-left"]).
329border_radius_pos_dirs(tl, ["top-left"]).
330border_radius_pos_dirs(tr, ["top-right"]).
331border_radius_pos_dirs(br, ["bottom-right"]).
332border_radius_pos_dirs(bl, ["bottom-left"]).
333
334border_radius_size("0px") --> "-none", !.
335border_radius_size("9999px") --> "-full", !.
336border_radius_size(Size) -->
337 "-", border_radius_size_multi(Cls),
338 { S is Cls * 0.25,
339 format(string(Size), "~wrem", [S]) }.
340
341border_radius_size_multi(0.5) --> "sm", !.
342border_radius_size_multi(1.5) --> "md", !.
343border_radius_size_multi(2) --> "lg", !.
344border_radius_size_multi(3) --> "xl", !.
345border_radius_size_multi(4) --> "2xl", !.
346border_radius_size_multi(6) --> "3xl".
347
348
349tailwind(Style) -->
350 "rounded",
351 optional(border_radius_pos(Pos), { Pos = false}),
352 optional(border_radius_size(Size), { Size = "0.25rem"}), !,
353 { Pos == false
354 -> Style = 'border-radius'(Size)
355 ; maplist({Size}/[D, St]>>(
356 format(atom(Attr), "border-~w-radius", [D]),
357 St =.. [Attr, Size]
358 ),
359 Pos,
360 Style) }.
361
362colour_border(special(S), S) :- !.
363colour_border(Colour, CssColour) :-
364 ( has_alpha(Colour)
365 -> Colour_ = Colour
366 ; colour_with_alpha(Colour, "var(--pl-border-opacity,1)", Colour_) ),
367 colour_css(Colour_, CssColour).
368
369tailwind('border-color'(ColourCss)) -->
370 "border-", colour(Colour), !,
371 { colour_border(Colour, ColourCss) }.
372
373tailwind('--pl-border-opacity'(Opacity)) -->
374 "border-opacity-", num(Num), !,
375 { value_unit_css(Num, Opacity, _{value_fn: div_100}) }.
376
377tailwind('border-style'(Style)) -->
378 "border-", one_of(["solid", "dashed", "dotted", "double", "none"], Style), !.
379
380divide_width_value(WidthVal) -->
381 "-", alternates([length(WidthVal), length_unit(WidthVal), num(WidthVal)]).
382
383divide_axis_styles(x, Width, ['border-right-width'(RStyle),
384 'border-left-width'(LStyle)]) :-
385 format(string(RStyle), "calc(~w * var(--pl-divide-x-reverse))", [Width]),
386 format(string(LStyle), "calc(~w * calc(1 - var(--pl-divide-x-reverse)))", [Width]).
387divide_axis_styles(y, Width, ['border-top-width'(TStyle),
388 'border-bottom-width'(BStyle)]) :-
389 format(string(TStyle), "calc(~w * var(--pl-divide-y-reverse))", [Width]),
390 format(string(BStyle), "calc(~w * calc(1 - var(--pl-divide-y-reverse)))", [Width]).
391
392tailwind('&'('> * + *'(Styles))) --> 393 "divide-", axis(axis(Axis)),
394 optional(divide_width_value(WidthVal), { WidthVal = length(1,px) }), !,
395 { value_unit_css(WidthVal, CssVal, _{zero_unit: "", number: _{unit: px}}),
396 divide_axis_styles(Axis, CssVal, Styles) }.
397
398direction_border_attr(t, 'border-top-width').
399direction_border_attr(r, 'border-right-width').
400direction_border_attr(b, 'border-bottom-width').
401direction_border_attr(l, 'border-left-width').
402
403colour_divide(special(S), S) :- !.
404colour_divide(Colour, CssColour) :-
405 ( has_alpha(Colour)
406 -> Colour_ = Colour
407 ; colour_with_alpha(Colour, "var(--pl-divide-opacity,1)", Colour_) ),
408 colour_css(Colour_, CssColour).
409
410tailwind('&'('> * + *'('border-color'(ColourCss)))) -->
411 "divide-", colour(Colour), !,
412 { colour_divide(Colour, ColourCss) }.
413
414tailwind('--pl-divide-opacity'(Opacity)) -->
415 "divide-opacity-", num(Number), !,
416 { value_unit_css(Number, Opacity, _{value_fn: div_100}) }.
417
418tailwind('&'('> * + *'('border-style'(Style)))) -->
419 "divide-", one_of(["solid", "dashed", "dotted", "double", "none"], Style), !.
420
421ring_colour(special(Colour), Colour) :- !.
422ring_colour(Colour, ColourCss) :-
423 has_alpha(Colour), !,
424 colour_css(Colour, ColourCss).
425ring_colour(Colour, ColourCss) :-
426 colour_with_alpha(Colour, "var(--pl-ring-opacity,1)", Colour_),
427 colour_css(Colour_, ColourCss).
428
429tailwind('--pl-ring-color'(ColourCss)) -->
430 "ring-", colour(Colour), !,
431 { ring_colour(Colour, ColourCss) }.
432
433tailwind('--pl-ring-opacity'(Opacity)) -->
434 "ring-opacity-", num(Number), !,
435 { value_unit_css(Number, Opacity, _{value_fn: div_100}) }.
436
437tailwind(['--pl-ring-offset-width'(OffWidth),
438 'box-shadow'("0 0 0 var(--pl-ring-offset-width) var(--pl-ring-offset-color), var(--pl-ring-shadow)")]) -->
439 "ring-offset-", alternates([length(X), length_unit(X), num(X)]), !,
440 { value_unit_css(X, OffWidth, _{zero_unit: "", number: _{unit: px}}) }.
441
442tailwind(['--pl-ring-offset-color'(OffColour),
443 'box-shadow'("0 0 0 var(--pl-ring-offset-width, 0px) var(--pl-ring-offset-color), var(--pl-ring-shadow)")]) -->
444 "ring-offset-", colour(Colour), !,
445 { ring_colour(Colour, OffColour) }.
446
447tailwind('--pl-ring-inset'("inset")) --> "ring-inset", !.
448tailwind('box-shadow'(Style)) -->
449 "ring-", alternates([length(Len), length_unit(Len), num(Len)]), !,
450 { value_unit_css(Len, LenCss, _{zero_unit: "", number: _{unit: px}}),
451 format(string(Style),
452 "var(--pl-ring-inset, ) 0 0 0 calc(~w + var(--pl-ring-offset-width,0px)) var(--pl-ring-color)",
453 [LenCss]) }.
455tailwind('box-shadow'("var(--pl-ring-inset, ) 0 0 0 calc(3px + var(--pl-ring-offset-width,0px)) var(--pl-ring-color)")) -->
456 "ring", !.
457
458border_direction(Attr) -->
459 "-", direction(direction(Dir)),
460 { direction_border_attr(Dir, Attr) }.
461
462border_width_val(Width) -->
463 "-", alternates([length(Len), length_unit(Len), num(Len)]),
464 { value_unit_css(Len, Width, _{zero_unit: "", number: _{unit: px}}) }.
465
467soft_optional(A, _) --> A, !.
468soft_optional(_, B) --> B.
469
475tailwind('border-width'(Width)) -->
476 "border", border_width_val(Width), !.
477tailwind(Style) -->
478 "border",
479 soft_optional(border_direction(Attr), { Attr = 'border-width' }),
480 soft_optional(border_width_val(Width), { Width = "1px" }), !,
481 { Style =.. [Attr, Width] }.
482
484
485flex_align_style(start, "flex-start").
486flex_align_style(end, "flex-end").
487flex_align_style(center, "center").
488flex_align_style(between, "space-between").
489flex_align_style(around, "space-around").
490flex_align_style(evenly, "space-evenly").
491
492tailwind('justify-content'(Justify)) -->
493 "justify-", one_of(["start", "end", "center", "between", "around", "evenly"],
494 Just), !,
495 { flex_align_style(Just, Justify) }.
496
497tailwind('justify-items'(Justify)) -->
498 "justify-items-",
499 one_of(["auto", "start" , "end", "center", "stretch"], Justify), !.
500
501tailwind('justify-self'(Justify)) -->
502 "justify-self-",
503 one_of(["auto", "start" , "end", "center", "stretch"], Justify), !.
504
505tailwind('align-content'(Align)) -->
506 "content-", one_of(["start", "end", "center", "between", "around", "evenly"],
507 A), !,
508 { flex_align_style(A, Align) }.
509
510flex_items_style(start, "flex-start") :- !.
511flex_items_style(end, "flex-end") :- !.
512flex_items_style(S, S).
513
514tailwind('align-items'(Align)) -->
515 "items-", one_of(["start", "end", "center", "baseline", "stretch"],
516 A), !,
517 { flex_items_style(A, Align) }.
518
519tailwind('align-self'(Align)) -->
520 "self-", one_of(["start", "end", "center", "stretch", "auto"],
521 A), !,
522 { flex_items_style(A, Align) }.
523
524place_content_place(between, "space-between") :- !.
525place_content_place(around, "space-around") :- !.
526place_content_place(evenly, "space-evenly") :- !.
527place_content_place(P, P).
528
529tailwind('place-content'(Place)) -->
530 "place-content-", one_of(["start", "end", "center", "between",
531 "around", "evenly", "stretch"], P), !,
532 { place_content_place(P, Place) }.
533
534tailwind('place-items'(P)) -->
535 "place-items-", one_of(["auto", "start", "end", "center", "stretch"], P).
536
537tailwind('place-self'(P)) -->
538 "place-self-", one_of(["auto", "start", "end", "center", "stretch"], P).
539
541
542shadow_size_style(sm, "0 1px 2px 0 rgba(0,0,0,0.05)").
543shadow_size_style(md, "0 4px 6px -1px rgba(0,0,0,0.1),0 2px 4px -1px rgba(0,0,0,0.06)").
544shadow_size_style(lg, "0 10px 15px -3px rgba(0,0,0,0.1),0 4px 6px -2px rgba(0,0,0,0.05)").
545shadow_size_style(xl, "0 20px 25px -5px rgba(0,0,0,0.1),0 10px 10px -5px rgba(0,0,0,0.04)").
546shadow_size_style('2xl', "0 25px 50px -12px rgba(0,0,0,0.25)").
547shadow_size_style(inner, "inset 0 2px 4px 0 rgba(0,0,0,0.06)").
548shadow_size_style(none, "0 0 #0000").
549
550tailwind(['--pl-shadow'(Shadow),
551 'box-shadow'("var(--pl-ring-offset-shadow,0 0 #0000),var(--pl-ring-shadow,0 0 #0000),var(--pl-shadow)")]) -->
552 "shadow-",
553 one_of(["sm", "md", "lg", "xl", "2xl", "inner", "none"],
554 Val), !,
555 { shadow_size_style(Val, Shadow) }.
556tailwind(['--pl-shadow'("0 1px 3px 0 rgba(0,0,0,0.1),0 1px 2px 0 rgba(0,0,0,0.06)"),
557 'box-shadow'("var(--pl-ring-offset-shadow,0 0 #0000),var(--pl-ring-shadow,0 0 #0000),var(--pl-shadow)")]) -->
558 "shadow", !.
559
560tailwind(opacity(Opacity)) -->
561 "opacity-", num(Num), !,
562 { value_unit_css(Num, Opacity, _{value_fn: div_100}) }.
563
565
566tailwind('grid-template-columns'(none)) --> "grid-cols-none", !.
567tailwind('grid-template-columns'(none)) --> "grid-cols-0", !.
568tailwind('grid-template-columns'(Style)) -->
569 "grid-cols-", integer(Int), !,
570 { format(string(Style), "repeat(~d, minmax(0, 1fr))", [Int]) }.
571
572tailwind('grid-column'(auto)) --> "col-auto", !.
573
574tailwind('grid-column'("-1 / 1")) --> "col-span-full", !.
575tailwind('grid-column'(Span)) -->
576 "col-span-", integer(Int), !,
577 { format(string(Span), "span ~d / span ~d", [Int, Int]) }.
578
579tailwind('grid-column-start'("auto")) --> "col-start-auto", !.
580tailwind('grid-column-start'(Start)) -->
581 "col-start-", integer(Start), !.
582
583tailwind('grid-template-rows'("none")) --> "grid-rows-none", !.
584tailwind('grid-template-rows'("none")) --> "grid-rows-0", !.
585tailwind('grid-template-rows'(Rows)) -->
586 "grid-rows-", integer(Int), !,
587 { format(string(Rows), "repeat(~d, minmax(0, 1fr))", [Int]) }.
588
589tailwind('grid-row'("auto")) --> "row-auto", !.
590
591tailwind('grid-row'("-1 / 1")) --> "row-span-full", !.
592tailwind('grid-row'(Span)) -->
593 "row-span-", integer(Int), !,
594 { format(string(Span), "span ~d / span ~d", [Int, Int]) }.
595
596tailwind('grid-row-start'("auto")) --> "row-start-auto", !.
597tailwind('grid-row-start'(Start)) --> "row-start-", integer(Start), !.
598
599grid_flow_style(row, "row").
600grid_flow_style(col, "col").
601grid_flow_style('row-dense', "row dense").
602grid_flow_style('col-dense', "col dense").
603
604tailwind('grid-auto-flow'(Flow)) -->
605 "grid-flow-", one_of(["row-dense", "col-dense", "row", "col"],
606 FlowType), !,
607 { grid_flow_style(FlowType, Flow) }.
608
609grid_auto_style(auto, "auto").
610grid_auto_style(min, "min-content").
611grid_auto_style(max, "max-content").
612grid_auto_style(fr, "minmax(0, 1fr)").
613
614tailwind('grid-auto-columns'(Cols)) -->
615 "auto-cols-", one_of(["auto", "min", "max", "fr"],
616 AutoType), !,
617 { grid_auto_style(AutoType, Cols) }.
618
619tailwind('grid-auto-rows'(Rows)) -->
620 "auto-rows-", one_of(["auto", "min", "max", "fr"],
621 AutoType), !,
622 { grid_auto_style(AutoType, Rows) }.
623
624gap_type(Val) -->
625 alternates([percentage(V), length(V), length_unit(V), num(V)]),
626 { value_unit_css(V, Val, _{zero_unit: "", number: _{unit: rem,
627 value_fn: div_4}}) }.
628
629tailwind('column-gap'(Val)) -->
630 "gap-x-", gap_type(Val), !.
631tailwind('row-gap'(Val)) -->
632 "gap-y-", gap_type(Val), !.
633tailwind('gap'(Val)) -->
634 "gap-", gap_type(Val), !.
635
637
638tailwind(appearance(none)) --> "appearance-none", !.
639
640tailwind(cursor(Type)) -->
641 "cursor-", one_of(["auto", "default", "pointer", "wait", "text", "move",
642 "not-allowed"], Type), !.
643
644outline_type(none, "2px solid transparent").
645outline_type(white, "2px dotted white").
646outline_type(black, "2px dotted black").
647
648tailwind(['outline-offset'("2px"), outline(Type)]) -->
649 "outline-", one_of(["none", "white", "black"], Type_), !,
650 { outline_type(Type_, Type) }.
651
652tailwind('pointer-events'(Events)) -->
653 "pointer-events-", one_of(["none", "auto"], Events), !.
654
655resize_type(none, "none").
656resize_type(x, "horizontal").
657resize_type(y, "vertical").
658
659tailwind(resize(Resize)) -->
660 "resize-", one_of(["none", "x", "y"], Type), !,
661 { resize_type(Type, Resize) }.
662tailwind(resize("both")) --> "resize", !.
663
664tailwind('user-select'(Type)) -->
665 "select-", one_of(["none", "text", "all", "auto"], Type), !.
666
668
672tailwind(width("100%")) --> "container", !.
673
674tailwind('box-sizing'("border-box")) --> "box-border", !.
675tailwind('box-sizing'("content-box")) --> "box-content", !.
676
677tailwind(display("none")) --> "hidden", !.
678tailwind(display(Display)) -->
679 one_of(["block", "inline-block", "flex", "inline-flex",
680 "inline-grid", "inline", "grid", "table-column-group",
681 "table-footer-group", "table-header-group",
682 "table-row-group",
683 "table-column", "table-cell", "table-row", "table-caption",
684 "table", "contents", "hidden", "flow-root"
685 ], Display), !.
686
687tailwind(float(Dir)) --> "float-", one_of(["left", "right", "none"], Dir), !.
688
689tailwind(clear(Dir)) -->
690 "clear-", one_of(["left", "right", "both", "none"], Dir), !.
691
692tailwind('object-fit'(Fit)) -->
693 "object-", one_of(["contain", "cover", "fill", "none", "scale-down"], Fit),
694 !.
695
696tailwind(Style) -->
697 "overflow-", axis(axis(Axis)), "-",
698 one_of(["auto", "hidden", "visible", "scroll"], Mode), !,
699 { format(atom(Prop), "overflow-~w", [Axis]),
700 Style =.. [Prop, Mode] }.
701tailwind(overflow(Mode)) -->
702 "overflow-", one_of(["auto", "hidden", "visible", "scroll"], Mode), !.
703
704tailwind(Style) -->
705 "overscroll-", axis(axis(Axis)), "-",
706 one_of(["auto", "contain", "none"], Mode), !,
707 { format(atom(Prop), "overscroll-~w", [Axis]),
708 Style =.. [Prop, Mode] }.
709tailwind(overscroll(Mode)) -->
710 "overscroll-", one_of(["auto", "contain", "none"], Mode), !.
711
712tailwind(position(Pos)) -->
713 one_of(["static", "fixed", "absolute", "relative", "sticky"], Pos), !.
714
715tailwind(Styles) -->
716 soft_optional(signus(S), { S = '+' }),
717 one_of(["top", "right", "bottom", "left",
718 "inset-x", "inset-y", "inset"], Mode),
719 "-",
720 alternates([length(Val), length_unit(Val), fraction(Val),
721 percentage(Val), full_100(Val), auto(Val),
722 num(Val)]), !,
723 { value_unit_css(Val, Value, _{signus: S,
724 zero_unit: "",
725 number: _{unit: rem, value_fn: div_4},
726 fraction: _{unit: "%", value_fn: mul_100}}),
727 positioning_mode_dirs(Mode, Dirs),
728 maplist({Value}/[Dir, Style]>>(Style =.. [Dir, Value]),
729 Dirs, Styles) }.
730
731positioning_mode_dirs(inset, [top, right, bottom, left]) :- !.
732positioning_mode_dirs('inset-x', [right, left]) :- !.
733positioning_mode_dirs('inset-y', [top, bottom]) :- !.
734positioning_mode_dirs(Dir, [Dir]).
735
736tailwind(visibility(Vis)) -->
737 one_of(["visible", "invisible"], Vis0), !,
738 { Vis0 == invisible -> Vis = hidden ; Vis = Vis0 }.
739
740tailwind('z-index'("auto")) --> "z-auto", !.
741tailwind('z-index'(Index)) --> "z-", integer(Index), !.
742
744
745tailwind(width(Width)) -->
746 "w-", alternates([length(Val), length_unit(Val), fraction(Val),
747 percentage(Val), full_100(Val), auto(Val),
748 screen_100vw(Val), min_content(Val), max_content(Val),
749 num(Val)]), !,
750 { value_unit_css(Val, Width, _{zero_unit: "",
751 number: _{unit: rem, value_fn: div_4},
752 fraction: _{unit: '%', value_fn: mul_100}}) }.
753
754tailwind('min-width'(Width)) -->
755 "min-w-", alternates([length(Val), length_unit(Val), fraction(Val),
756 percentage(Val), full_100(Val), auto(Val),
757 screen_100vw(Val), min_content(Val), max_content(Val),
758 num(Val)]), !,
759 { value_unit_css(Val, Width, _{zero_unit: "",
760 number: _{unit: rem, value_fn: div_4},
761 fraction: _{unit: '%', value_fn: mul_100}}) }.
762
763tailwind('max-width'(Width)) -->
764 "max-w-", alternates([length(Val), length_unit(Val), fraction(Val),
765 percentage(Val), full_100(Val), unset(Val),
766 screen_100vw(Val), min_content(Val), max_content(Val),
767 num(Val)]), !,
768 { value_unit_css(Val, Width, _{zero_unit: "",
769 number: _{unit: rem, value_fn: div_4},
770 fraction: _{unit: '%', value_fn: mul_100}}) }.
771
772tailwind(height(Height)) -->
773 "h-", alternates([length(Val), length_unit(Val), fraction(Val),
774 percentage(Val), full_100(Val), auto(Val),
775 screen_100vw(Val), min_content(Val), max_content(Val),
776 num(Val)]), !,
777 { value_unit_css(Val, Height, _{zero_unit: "",
778 number: _{unit: rem, value_fn: div_4},
779 fraction: _{unit: '%', value_fn: mul_100}}) }.
780
781tailwind('min-height'(Height)) -->
782 "min-h-", alternates([length(Val), length_unit(Val), fraction(Val),
783 percentage(Val), full_100(Val), auto(Val),
784 screen_100vw(Val), min_content(Val), max_content(Val),
785 num(Val)]), !,
786 { value_unit_css(Val, Height, _{zero_unit: "",
787 number: _{unit: rem, value_fn: div_4},
788 fraction: _{unit: '%', value_fn: mul_100}}) }.
789
790tailwind('max-height'(Height)) -->
791 "max-h-", alternates([length(Val), length_unit(Val), fraction(Val),
792 percentage(Val), full_100(Val), unset(Val),
793 screen_100vw(Val), min_content(Val), max_content(Val),
794 num(Val)]), !,
795 { value_unit_css(Val, Height, _{zero_unit: "",
796 number: _{unit: rem, value_fn: div_4},
797 fraction: _{unit: '%', value_fn: mul_100}}) }.
798
800
801dir_axis_props(axis(x), [left, right]).
802dir_axis_props(axis(y), [top, bottom]).
803dir_axis_props(direction(t), [top]).
804dir_axis_props(direction(r), [right]).
805dir_axis_props(direction(b), [bottom]).
806dir_axis_props(direction(l), [left]).
807
808tailwind(padding(Padding)) -->
809 soft_optional(signus(S), { S = '+' }),
810 "p-", alternates([length(Val), length_unit(Val), num(Val)]), !,
811 { value_unit_css(Val, Padding, _{signus: S, zero_unit: "",
812 number: _{unit: rem, value_fn: div_4}}) }.
813tailwind(Styles) -->
814 soft_optional(signus(S), { S = '+' }),
815 "p", alternates([axis(A), direction(A)]), "-",
816 alternates([length(Val), length_unit(Val), num(Val)]), !,
817 { value_unit_css(Val, Padding, _{signus: S, zero_unit: "",
818 number: _{unit: rem, value_fn: div_4}}),
819 dir_axis_props(A, Props),
820 maplist({Padding}/[Prop, Style]>>(
821 format(atom(Attr), "padding-~w", [Prop]),
822 Style =.. [Attr, Padding]),
823 Props, Styles) }.
824
825tailwind(margin(Margin)) -->
826 soft_optional(signus(S), { S = '+' }),
827 "m-", alternates([length(Val), length_unit(Val), num(Val)]), !,
828 { value_unit_css(Val, Margin, _{signus: S, zero_unit: "",
829 number: _{unit: rem, value_fn: div_4}}) }.
830tailwind(Styles) -->
831 soft_optional(signus(S), { S = '+' }),
832 "m", alternates([axis(A), direction(A)]), "-",
833 alternates([length(Val), length_unit(Val), num(Val)]), !,
834 { value_unit_css(Val, Margin, _{signus: S, zero_unit: "",
835 number: _{unit: rem, value_fn: div_4}}),
836 dir_axis_props(A, Props),
837 maplist({Margin}/[Prop, Style]>>(
838 format(atom(Attr), "margin-~w", [Prop]),
839 Style =.. [Attr, Margin]),
840 Props, Styles) }.
841
842space_between_reverse(true) --> "-reverse".
843space_between_reverse(false) --> [].
844
845space_between_prop(x, false, left).
846space_between_prop(x, true, right).
847space_between_prop(y, false, top).
848space_between_prop(y, true, bottom).
849
850tailwind('&'('> * + *'(Style))) -->
851 soft_optional(signus(S), { S = '+' }),
852 "space-", axis(axis(A)), "-",
853 alternates([length(Val), length_unit(Val), num(Val)]),
854 space_between_reverse(Rev), !,
855 { space_between_prop(A, Rev, Dir), !,
856 format(atom(Prop), "margin-~w", [Dir]),
857 value_unit_css(Val, Value, _{signus: S, zero_unit: "",
858 number: _{unit: rem, value_fn: div_4}}),
859 Style =.. [Prop, Value] }.
860
862
863tailwind(fill(ColourCss)) -->
864 "fill-", colour(Colour), !,
865 { colour_css(Colour, ColourCss) }.
866
867tailwind(stroke(ColourCss)) -->
868 "stroke-", colour(Colour), !,
869 { colour_css(Colour, ColourCss) }.
870
871tailwind('stroke-width'(Thickness)) -->
872 "stroke-", num(number(Thickness)), !.
873
875
876tailwind('border-collapse'(Type)) -->
877 "border-", one_of(["collapse", "separate"], Type), !.
878
879tailwind('table-layout'(Type)) -->
880 "table-", one_of(["auto", "fixed"], Type), !.
881
883
884tailwind(transform(none)) --> "transform-none", !.
885tailwind(['--pl-translate-x'(0),
886 '--pl-translate-y'(0),
887 '--pl-rotate'(0),
888 '--pl-skew-x'(0),
889 '--pl-skew-y'(0),
890 '--pl-scale-x'(0),
891 '--pl-scale-y'(0),
892 transform("translate3d(var(--pl-translate-x),var(--pl-translate-y),0) rotate(var(--pl-rotate)) skewX(var(--pl-skew-x)) skewY(var(--pl-skew-y)) scaleX(var(--pl-scale-x)) scaleY(var(--pl-scale-y))")
893 ]) -->
894 "transform-gpu", !.
895tailwind(['--pl-translate-x'(0),
896 '--pl-translate-y'(0),
897 '--pl-rotate'(0),
898 '--pl-skew-x'(0),
899 '--pl-skew-y'(0),
900 '--pl-scale-x'(0),
901 '--pl-scale-y'(0),
902 transform("translateX(var(--pl-translate-x)) translateY(var(--pl-translate-y)) rotate(var(--pl-rotate)) skewX(var(--pl-skew-x)) skewY(var(--pl-skew-y)) scaleX(var(--pl-scale-x)) scaleY(var(--pl-scale-y))")
903 ]) -->
904 "transform", !.
905
906transform_origin_pos('top-left', "top left") :- !.
907transform_origin_pos('top-right', "top right") :- !.
908transform_origin_pos('bottom-left', "bottom left") :- !.
909transform_origin_pos('bottom-right', "bottom right") :- !.
910transform_origin_pos(P, P).
911
912tailwind('transform-origin'(Origin)) -->
913 "origin-", one_of(["top-left", "top-right", "top",
914 "bottom-left", "bottom-right", "bottom",
915 "left", "center", "right"],
916 Orig), !,
917 { transform_origin_pos(Orig, Origin) }.
918
919tailwind(Style) -->
920 soft_optional(signus(S), { S = '+' }),
921 "scale-", axis(axis(A)), "-", num(Val), !,
922 { value_unit_css(Val, CssVal, _{signus: S, value_fn: div_100}),
923 format(atom(Prop), "--pl-scale-~w", [A]),
924 Style =.. [Prop, CssVal] }.
925tailwind(['--pl-scale-x'(CssVal), '--pl-scale-y'(CssVal)]) -->
926 soft_optional(signus(S), { S = '+' }),
927 "scale-", num(Val), !,
928 { value_unit_css(Val, CssVal, _{signus: S, value_fn: div_100}) }.
929
930tailwind('--pl-rotate'(Rotate)) -->
931 soft_optional(signus(S), { S = '+' }),
932 "rotate-", alternates([angle(V), num(V)]), !,
933 { value_unit_css(V, Rotate, _{signus: S, zero_unit: "",
934 number: _{unit: deg}}) }.
935
936tailwind(Style) -->
937 soft_optional(signus(S), { S = '+' }),
938 "translate-", axis(axis(A)), "-",
939 alternates([length(V), length_unit(V), fraction(V),
940 percentage(V), full_100(V), num(V)]), !,
941 { format(atom(Prop), "--pl-translate-~w", [A]),
942 value_unit_css(V, Val, _{signus: S, zero_unit: "",
943 number: _{unit: rem, value_fn: div_4},
944 fraction: _{unit: "%", value_fn: mul_100}}),
945 Style =.. [Prop, Val] }.
946
947tailwind(Style) -->
948 soft_optional(signus(S), { S = '+' }),
949 "skew-", axis(axis(A)), "-", alternates([angle(V), num(V)]),
950 { value_unit_css(V, Skew, _{signus: S, zero_unit: "",
951 number: _{unit: deg}}),
952 format(atom(Prop), "--pl-skew-~w", [A]),
953 Style =.. [Prop, Skew] }.
954
956
957default_font_family(sans, "ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, \"Helvetica Neue\", Arial, \"Noto Sans\", sans-serif, \"Apple Color Emoji\", \"Segoe UI Emoji\", \"Segoe UI Symbol\", \"Noto Color Emoji\"").
958default_font_family(serif, "ui-serif, Georgia, Cambria, \"Times New Roman\", Times, serif").
959default_font_family(mono, "ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, \"Liberation Mono\", \"Courier New\", monospace").
960
961tailwind('font-family'(FontFamily)) -->
962 "font-", one_of(["sans", "serif", "mono"], Family), !,
963 { default_font_family(Family, FontFamily) }.
964
965tailwind(['font-size'(SizeRem), 'line-height'(HeightRem)]) -->
966 "text-", one_of(["xs", "sm", "base", "lg", "xl", "2xl", "3xl",
967 "4xl", "5xl", "6xl", "7xl", "8xl", "9xl"],
968 SzCls), !,
969 { font_class_size_height(SzCls, Size, Height),
970 format(string(SizeRem), "~wrem", [Size]),
971 format(string(HeightRem), "~wrem", [Height]) }.
972
973font_class_size_height(xs, 0.75, 1).
974font_class_size_height(sm, 0.875, 1.25).
975font_class_size_height(base, 1, 1.5).
976font_class_size_height(lg, 1.125, 1.75).
977font_class_size_height(xl, 1.25, 1.75).
978font_class_size_height('2xl', 1.5, 2).
979font_class_size_height('3xl', 1.875, 2.25).
980font_class_size_height('4xl', 2.25, 2.5).
981font_class_size_height('5xl', 3, 1).
982font_class_size_height('6xl', 3.75, 1).
983font_class_size_height('7xl', 4.5, 1).
984font_class_size_height('8xl', 6, 1).
985font_class_size_height('9xl', 8, 1).
986
988tailwind('font-size'(Size)) -->
989 "font-size-", alternates([length(V), fraction(V), percentage(V), num(V)]), !,
990 { value_unit_css(V, Size, _{number: _{unit: rem, value_fn: div_4},
991 fraction: _{unit: '%', value_fn: mul_100}}) }.
992
993tailwind(['-webkit-font-smoothing'("antialiased"),
994 '-moz-osx-font-smoothing'("grayscale")]) -->
995 "antialiased", !.
996tailwind(['-webkit-font-smoothing'("auto"),
997 '-moz-osx-font-smoothing'("auto")]) -->
998 "subpixel-antialiased", !.
999
1000tailwind('font-style'("italic")) --> "italic", !.
1001tailwind('font-style'("normal")) --> "not-italic", !.
1002
1003tailwind('font-weight'(Weight)) -->
1004 "font-", one_of(["thin", "extralight", "light", "normal",
1005 "medium", "semibold", "bold", "extrabold", "black"],
1006 WeightType), !,
1007 { font_type_weight(WeightType, Weight) }.
1008
1009font_type_weight(thin, 100).
1010font_type_weight(extralight, 200).
1011font_type_weight(light, 300).
1012font_type_weight(normal, 400).
1013font_type_weight(medium, 500).
1014font_type_weight(semibold, 600).
1015font_type_weight(bold, 700).
1016font_type_weight(extrabold, 800).
1017font_type_weight(black, 900).
1018
1019tailwind('font-variant-numeric'(Variant)) -->
1020 one_of(["normal-nums", "ordinal", "slashed-zero",
1021 "lining-nums", "oldstyle-nums", "proportional-nums",
1022 "tabular-nums", "diagonal-fractions", "stacked-fractions"],
1023 Variant), !.
1024
1025tailwind('letter-spacing'(SpacingEm)) -->
1026 "tracking-", one_of(["tighter", "tight", "normal",
1027 "wider", "widest", "wide"], Size), !,
1028 { letter_spacing(Size, Spacing),
1029 format(string(SpacingEm), "~wem", [Spacing]) }.
1030
1031letter_spacing(tighter, -0.05).
1032letter_spacing(tight, -0.025).
1033letter_spacing(normal, 0).
1034letter_spacing(wide, 0.025).
1035letter_spacing(wider, 0.05).
1036letter_spacing(widest, 0.1).
1037
1038tailwind('line-height'(LineHeight)) -->
1039 "leading-", one_of(["none", "tight", "snug", "normal",
1040 "relaxed", "loose"], SizeName), !,
1041 { line_height_size(SizeName, LineHeight) }.
1042tailwind('line-height'(LineHeight)) -->
1043 "leading-", num(Size), !,
1044 { value_unit_css(Size, LineHeight, _{zero_unit: "",
1045 number: _{unit: rem,
1046 value_fn: div_4}}) }.
1047
1048
1049line_height_size(none, 1).
1050line_height_size(tight, 1.25).
1051line_height_size(snug, 1.375).
1052line_height_size(normal, 1.5).
1053line_height_size(relaxed, 1.625).
1054line_height_size(loose, 2).
1055
1057tailwind('line-height'(Height)) -->
1058 "line-height-",
1059 alternates([length(V), fraction(V), percentage(V), num(V)]), !,
1060 { value_unit_css(V, Height, _{fraction: _{unit: '%', value_fn: mul_100}}) }.
1061
1062tailwind('list-style-type'(Type)) -->
1063 "list-", one_of(["none", "disc", "decimal"], Type), !.
1064
1065tailwind('list-style-position'(Type)) -->
1066 "list-", one_of(["inside", "outside"], Type), !.
1067
1068tailwind('&'('::placeholder'(Style))) -->
1069 "placeholder-", colour(Colour), !,
1070 { colour_placeholder(Colour, Style) }.
1071
1072colour_placeholder(special(S), S) :- !.
1073colour_placeholder(Colour, CssColour) :-
1074 ( has_alpha(Colour)
1075 -> Colour_ = Colour
1076 ; colour_with_alpha(Colour, "var(--pl-placeholder-opacity,1)", Colour_) ),
1077 colour_css(Colour_, CssColour).
1078
1079tailwind('--pl-placeholder-opacity'(Opacity)) -->
1080 "placeholder-opacity-", num(Val), !,
1081 { value_unit_css(Val, Opacity, _{value_fn: div_100}) }.
1082
1083tailwind('text-align'(Align)) -->
1084 "text-", one_of(["left", "center", "right", "justify"], Align), !.
1085
1086tailwind(color(ColourCss)) -->
1087 "text-", colour(Colour), !,
1088 { colour_text(Colour, ColourCss) }.
1089
1090colour_text(special(S), S) :- !.
1091colour_text(Colour, CssColour) :-
1092 ( has_alpha(Colour)
1093 -> Colour_ = Colour
1094 ; colour_with_alpha(Colour, "var(--pl-text-opacity,1)", Colour_) ),
1095 colour_css(Colour_, CssColour).
1096
1097tailwind('--pl-text-opacity'(Opacity)) -->
1098 "text-opacity-", num(Num), !,
1099 { value_unit_css(Num, Opacity, _{value_fn: div_100}) }.
1100
1101tailwind('text-decoration'("none")) --> "no-underline", !.
1102tailwind('text-decoration'(Decoration)) -->
1103 one_of(["underline", "line-through"], Decoration), !.
1104
1105tailwind('text-transform'("none")) --> "normal-case", !.
1106tailwind('text-transform'(Trans)) -->
1107 one_of(["uppercase", "lowercase", "capitalize"], Trans), !.
1108
1109tailwind([overflow(hidden),
1110 'text-overflow'(ellipsis),
1111 'white-space'(nowrap)]) -->
1112 "truncate", !.
1113tailwind('text-overflow'(ellipsis)) --> "overflow-ellipsis", !.
1114tailwind('text-overflow'(clip)) --> "overflow-clip", !.
1115
1116tailwind('vertical-align'(Align)) -->
1117 "align-", one_of(["baseline", "top", "middle", "bottom",
1118 "text-top", "text-bottom"], Align), !.
1119
1120tailwind('white-space'(Control)) -->
1121 "whitespace-", one_of(["normal", "nowrap", "pre-line", "pre-wrap",
1122 "pre"], Control), !.
1123
1124tailwind(['overflow-wrap'(normal), 'word-break'(normal)]) -->
1125 "break-normal", !.
1126tailwind('overflow-wrap'("break-word")) --> "break-words", !.
1127tailwind('word-break'("break-all")) --> "break-all", !
Tailwind CSS grammar
DCGs for parsing Tailwind selectors to the corresponding CSS