Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
42 changes: 39 additions & 3 deletions lib/borders.ml
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,10 @@ type rounded_size =
| Rsz_theme of string
(* radius named by a project [--radius-*] token (rounded-blob) *)
| Rsz_arbitrary of string * Css.length
| Rsz_raw of string * string
(* rounded-[foo]: a corner names its own longhands, so a bracket no length
reader took still reaches them and the value is forwarded verbatim -
Tailwind's token-stream contract. *)

module Handler = struct
open Style
Expand Down Expand Up @@ -412,6 +416,26 @@ module Handler = struct
Shared by both the sized and arbitrary radius utilities; [Corner.All] uses
the [border-radius] shorthand, all others target the matching
corner/logical properties. *)
(* The longhands each corner names, for a value no typed setter can hold. *)
let radius_properties_for_position = function
| Corner.All -> [ "border-radius" ]
| Corner.Top -> [ "border-top-left-radius"; "border-top-right-radius" ]
| Corner.Right ->
[ "border-top-right-radius"; "border-bottom-right-radius" ]
| Corner.Bottom ->
[ "border-bottom-right-radius"; "border-bottom-left-radius" ]
| Corner.Left -> [ "border-top-left-radius"; "border-bottom-left-radius" ]
| Corner.Top_left -> [ "border-top-left-radius" ]
| Corner.Top_right -> [ "border-top-right-radius" ]
| Corner.Bottom_right -> [ "border-bottom-right-radius" ]
| Corner.Bottom_left -> [ "border-bottom-left-radius" ]
| Corner.Start -> [ "border-start-start-radius"; "border-end-start-radius" ]
| Corner.End -> [ "border-start-end-radius"; "border-end-end-radius" ]
| Corner.Start_start -> [ "border-start-start-radius" ]
| Corner.Start_end -> [ "border-start-end-radius" ]
| Corner.End_start -> [ "border-end-start-radius" ]
| Corner.End_end -> [ "border-end-end-radius" ]

let radius_decls_for_position pos (len : Css.length) : Css.declaration list =
match pos with
| Corner.All -> [ Css.border_radius (radius_value len) ]
Expand Down Expand Up @@ -499,6 +523,11 @@ module Handler = struct
(decl :: radius_decls_for_position pos (Var r : Css.length))
))
| Rsz_arbitrary (_, len) -> style (radius_decls_for_position pos len)
| Rsz_raw (_, value) ->
style
(List.filter_map
(fun property -> Parse.opaque_declaration property value)
(radius_properties_for_position pos))

(* Outline style variable - used by outline utilities that set the style *)
let outline_style_var =
Expand Down Expand Up @@ -961,7 +990,10 @@ module Handler = struct
let inner = Parse.bracket_inner v in
match parse_length inner with
| Some len -> Ok (Rounded (Corner.All, Rsz_arbitrary (inner, len)))
| None -> err_not_utility)
| None -> (
match Parse.arbitrary_declaration_value inner with
| Some raw -> Ok (Rounded (Corner.All, Rsz_raw (inner, raw)))
| None -> err_not_utility))
| [ "rounded"; tok ] -> (
match rounded_size_of_string tok with
| Some size -> Ok (Rounded (Corner.All, size))
Expand All @@ -976,7 +1008,11 @@ module Handler = struct
let inner = Parse.bracket_inner v in
match (corner_of_string pos, parse_length inner) with
| Some pos, Some len -> Ok (Rounded (pos, Rsz_arbitrary (inner, len)))
| _ -> err_not_utility)
| Some pos, None -> (
match Parse.arbitrary_declaration_value inner with
| Some raw -> Ok (Rounded (pos, Rsz_raw (inner, raw)))
| None -> err_not_utility)
| None, _ -> err_not_utility)
| [ "rounded"; pos; size ] -> (
match (corner_of_string pos, rounded_size_of_string size) with
| Some pos, Some size -> Ok (Rounded (pos, size))
Expand Down Expand Up @@ -1137,7 +1173,7 @@ module Handler = struct
| Rsz_4xl -> "-4xl"
| Rsz_full -> "-full"
| Rsz_theme name -> "-" ^ name
| Rsz_arbitrary (raw, _) -> "-[" ^ raw ^ "]"
| Rsz_arbitrary (raw, _) | Rsz_raw (raw, _) -> "-[" ^ raw ^ "]"
in
"rounded" ^ pos_str ^ size_str
| Outline -> "outline"
Expand Down
50 changes: 46 additions & 4 deletions lib/position.ml
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,12 @@ let read_paren_calc inner : Css.length Css.calc option =
the negative as [calc((a + b) * -1)], where the group is a calc
sub-expression; the positive it writes as [top: (a + b)], which is no
declaration a browser accepts, so there is nothing to agree with. *)
(* A bracket no length reader took is still one declaration value, which the
side's own longhand takes verbatim. *)
let bracket_token_stream s =
if not (Parse.is_bracket_value s) then None
else Parse.arbitrary_declaration_value (Parse.bracket_inner s)

let parse_bracket_length ?(negate = false) s : Css.length option =
if not (Parse.is_bracket_value s) then None
else
Expand Down Expand Up @@ -123,6 +129,20 @@ module Side = struct

(* What the side writes. [start] and [inset-s] name one property under two
spellings, as [end] and [inset-e] do. *)
(* The longhand each side names, for a value no typed setter can hold. *)
let properties = function
| Top -> [ "top" ]
| Right -> [ "right" ]
| Bottom -> [ "bottom" ]
| Left -> [ "left" ]
| Inset -> [ "inset" ]
| Inset_x -> [ "inset-inline" ]
| Inset_y -> [ "inset-block" ]
| Start | Inset_s -> [ "inset-inline-start" ]
| End | Inset_e -> [ "inset-inline-end" ]
| Inset_bs -> [ "inset-block-start" ]
| Inset_be -> [ "inset-block-end" ]

let declarations side (len : Css.length) =
match side with
| Top -> [ Css.top len ]
Expand Down Expand Up @@ -227,6 +247,11 @@ module Handler = struct
| Pos_arbitrary of Side.t * string * Css.length
(* raw bracket suffix kept for the class name, value already signed *)
| Neg_pos_arbitrary of Side.t * string * Css.length
| Pos_raw of Side.t * string * string
(* top-[foo]: an inset side writes one longhand, so a bracket no length
reader took still names it and the value is forwarded verbatim -
Tailwind's token-stream contract. *)
| Neg_pos_raw of Side.t * string * string
| Pos_named of Side.t * string
| Neg_pos_named of Side.t * string
(* theme token reference like inset-shadowned *)
Expand Down Expand Up @@ -316,6 +341,11 @@ module Handler = struct
style (Side.declarations side (Pct (-.frac_pct f)))
| Pos_arbitrary (side, _, len) | Neg_pos_arbitrary (side, _, len) ->
style (Side.declarations side len)
| Pos_raw (side, _, value) | Neg_pos_raw (side, _, value) ->
style
(List.filter_map
(fun property -> Parse.opaque_declaration property value)
(Side.properties side))
| Pos_named (side, name) ->
style (Side.declarations side (named_inset_value theme name))
| Neg_pos_named (side, name) ->
Expand Down Expand Up @@ -421,6 +451,8 @@ module Handler = struct
| Neg_pos_fraction (side, _)
| Pos_arbitrary (side, _, _)
| Neg_pos_arbitrary (side, _, _)
| Pos_raw (side, _, _)
| Neg_pos_raw (side, _, _)
| Pos_named (side, _)
| Neg_pos_named (side, _) ->
side_slot side
Expand Down Expand Up @@ -486,14 +518,22 @@ module Handler = struct
| Some len -> Ok (Pos_arbitrary (side, n, len))
| None when Parse.is_valid_theme_name n && is_named_inset theme n ->
Ok (Pos_named (side, n))
| None -> Error (`Msg "invalid")
| None -> (
match bracket_token_stream n with
| Some raw -> Ok (Pos_raw (side, n, raw))
| None -> Error (`Msg "invalid"))
in
let neg_arbitrary_or_named side n =
match parse_bracket_length ~negate:true n with
| Some len -> Ok (Neg_pos_arbitrary (side, n, len))
| None when Parse.is_valid_theme_name n && is_named_inset theme n ->
Ok (Neg_pos_named (side, n))
| None -> Error (`Msg "invalid")
| None -> (
(* [calc(<value> * -1)] is what a negated arbitrary writes whatever
the unit, and a value no reader took is no exception. *)
match bracket_token_stream n with
| Some raw -> Ok (Neg_pos_raw (side, n, "calc(" ^ raw ^ " * -1)"))
| None -> Error (`Msg "invalid"))
in
(* A fraction, then the side's own scale, then the shared tail. Every inset
side reads all three, so the suffix vocabulary is one function of the
Expand Down Expand Up @@ -688,8 +728,10 @@ module Handler = struct
Side.name side ^ "-" ^ Spacing.pp_spacing_suffix sp
| Neg_pos_spacing (side, sp) ->
"-" ^ Side.name side ^ "-" ^ Spacing.pp_spacing_suffix sp
| Pos_arbitrary (side, raw, _) -> Side.name side ^ "-" ^ raw
| Neg_pos_arbitrary (side, raw, _) -> "-" ^ Side.name side ^ "-" ^ raw
| Pos_arbitrary (side, raw, _) | Pos_raw (side, raw, _) ->
Side.name side ^ "-" ^ raw
| Neg_pos_arbitrary (side, raw, _) | Neg_pos_raw (side, raw, _) ->
"-" ^ Side.name side ^ "-" ^ raw
| Pos_fraction (side, f) -> Side.name side ^ "-" ^ f
| Neg_pos_fraction (side, f) -> "-" ^ Side.name side ^ "-" ^ f
| Pos_named (side, name) -> Side.name side ^ "-" ^ name
Expand Down
13 changes: 5 additions & 8 deletions test/test_position.ml
Original file line number Diff line number Diff line change
Expand Up @@ -508,14 +508,11 @@ let negative_named_inset_on_every_side () =
accepts *)
check_themed theme "-top-[(var(--a)+var(--b))]"
[ "top:calc((var(--a) + var(--b))*-1)" ];
Test_helpers.check_invalid_input
~why:
(Test_helpers.Diverges
"Tailwind writes the group out unwrapped, as top: (var(--a) + \
var(--b)); tw refuses the class rather than emit a declaration no \
browser reads")
(module Tw.Position.Handler)
"top-[(var(--a)+var(--b))]";
(* Unsigned, the group is no length either, so it goes to the side's own
longhand as the token stream it is - the same text the CLI writes, which no
browser reads and both sides therefore agree on. *)
Test_helpers.check_declarations "top-[(var(--a)+var(--b))]"
[ "top:(var(--a)+var(--b))" ];
(* and a name the theme binds in neither namespace is still no utility *)
Test_helpers.check_invalid_input (module Tw.Position.Handler) "-top-level";
Test_helpers.check_invalid_input (module Tw.Position.Handler) "-bottom-right"
Expand Down
Loading