package tw
sectionYPositions = computeSectionYPositions($el), 10)"
x-init="setTimeout(() => sectionYPositions = computeSectionYPositions($el), 10)"
>
Type-safe Tailwind CSS v4 in OCaml
Install
dune-project
Dependency
Authors
Maintainers
Sources
tw-1.1.0.tbz
sha256=48754ab34d0a97c37f5f2dbf50ce46747ec0ca6d483f5adbb7305fc247fb5315
sha512=f43621b49e77adc23fab3c968e5041188e428228d1930b89c307fc8916c428f1943a5d74c21467219077247021f0ba83fda9234b0dd119dfd14b7f9746332bf7
doc/src/tw/masks.ml.html
Source file masks.ml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763(** Mask utilities for CSS masking. Provides utilities for mask-image, mask-composite, mask-mode, mask-type, mask-size, mask-position, mask-repeat, mask-clip, and mask-origin. *) module Css = Cascade.Css module Handler = struct open Style open Css (* The position keywords [mask-<position>] accepts. *) module Keyword = struct type t = | Bottom | Bottom_left | Bottom_right | Center | Left | Right | Top | Top_left | Top_right end (* The longhands an arbitrary mask bracket is written into, each beside the [-webkit-] spelling this family writes with it. *) module Longhand = struct type t = Image | Position | Size let properties = function | Image -> [ "-webkit-mask-image"; "mask-image" ] | Position -> [ "-webkit-mask-position"; "mask-position" ] | Size -> [ "-webkit-mask-size"; "mask-size" ] (* The slot Tailwind's property table gives each one. *) let rank = function Image -> 209 | Size -> 260 | Position -> 262 end (* A bracket no reader here takes. Tailwind writes it into the longhand the class names and leaves the value spelled as the author wrote it, so whether it means anything is the browser's answer rather than tw's. *) type opaque = { spelling : string; (** the class as written, which prints back *) longhand : Longhand.t; value : string; (** the bracket's contents, decoded but not read *) } type t = | No_mask | Add | Exclude | Intersect | Subtract | Alpha | Luminance | Match | Type_alpha | Type_luminance | Auto | Contain | Cover | Position of Keyword.t | No_repeat | Repeat | Repeat_round | Repeat_space | Repeat_x | Repeat_y | Clip_border | Clip_padding | Clip_content | Clip_fill | Clip_stroke | Clip_view | No_clip | Origin_border | Origin_padding | Origin_content | Origin_fill | Origin_stroke | Origin_view (* Bracket notation *) | Bracket_contain | Bracket_cover | Bracket_size of string | Bracket_length of string | Bracket_position of string * Css.position_value list | Bracket_typed_position of string * Css.position_value list | Bracket_image_var of string | Bracket_url of string | Bracket_url_var of string | Bracket_var of string | Bracket_image of string (* Sub-property bracket notation: mask-position-[...], mask-size-[...] *) | Position_bracket of string * Css.position_value list | Position_bracket_var of string | Size_bracket of string | Size_bracket_var of string | Bracket_opaque of opaque let name = "masks" (* After the backgrounds and the mask-gradient utilities, before fill and stroke and before padding - Tailwind's own order. *) let priority _ = 21 (* The composite and mode utilities write their [-webkit-] longhand twice: that is what Tailwind's minified sheet carries for them, and the site comparison reads the two sheets byte for byte. *) let mask_none = style [ Css.webkit_mask_image Css.None; Css.mask_image Css.None ] let mask_add = style [ Css.webkit_mask_composite Source_over; Css.webkit_mask_composite Source_over; Css.mask_composite Css.Add; ] let mask_exclude = style [ Css.webkit_mask_composite Xor; Css.webkit_mask_composite Xor; Css.mask_composite Css.Exclude; ] let mask_intersect = style [ Css.webkit_mask_composite Source_in; Css.webkit_mask_composite Source_in; Css.mask_composite Css.Intersect; ] let mask_subtract = style [ Css.webkit_mask_composite Source_out; Css.webkit_mask_composite Source_out; Css.mask_composite Css.Subtract; ] let mask_alpha = style [ Css.webkit_mask_source_type Css.Alpha; Css.webkit_mask_source_type Css.Alpha; Css.mask_mode Css.Alpha; ] let mask_luminance = style [ Css.webkit_mask_source_type Css.Luminance; Css.webkit_mask_source_type Css.Luminance; Css.mask_mode Css.Luminance; ] let mask_match = style [ Css.webkit_mask_source_type Css.Auto; Css.webkit_mask_source_type Css.Auto; Css.mask_mode Match_source; ] let mask_type_alpha = style [ Css.mask_type Css.Alpha ] let mask_type_luminance = style [ Css.mask_type Css.Luminance ] (* mask-size *) let mask_auto = style [ Css.webkit_mask_size Css.Auto; Css.mask_size Css.Auto ] let mask_contain = style [ Css.webkit_mask_size Css.Contain; Css.mask_size Css.Contain ] let mask_cover = style [ Css.webkit_mask_size Css.Cover; Css.mask_size Css.Cover ] (* mask-position *) let mask_position' pos = let pos_val : Css.position_value list = match pos with | Keyword.Bottom -> [ Center_bottom ] | Keyword.Bottom_left -> [ XY (Pct 0., Pct 100.) ] | Keyword.Bottom_right -> [ XY (Pct 100., Pct 100.) ] | Keyword.Center -> [ Center ] | Keyword.Left -> [ Single (Pct 0.) ] | Keyword.Right -> [ Single (Pct 100.) ] | Keyword.Top -> [ Center_top ] | Keyword.Top_left -> [ XY (Pct 0., Pct 0.) ] | Keyword.Top_right -> [ XY (Pct 100., Pct 0.) ] in style [ Css.webkit_mask_position pos_val; Css.mask_position pos_val ] (* mask-repeat *) let mask_no_repeat' = style [ Css.webkit_mask_repeat Css.No_repeat; Css.mask_repeat Css.No_repeat ] let mask_repeat' = style [ Css.webkit_mask_repeat Css.Repeat; Css.mask_repeat Css.Repeat ] let mask_repeat_round' = style [ Css.webkit_mask_repeat Round; Css.mask_repeat Round ] let mask_repeat_space' = style [ Css.webkit_mask_repeat Space; Css.mask_repeat Space ] let mask_repeat_x' = style [ Css.webkit_mask_repeat Css.Repeat_x; Css.mask_repeat Css.Repeat_x ] let mask_repeat_y' = style [ Css.webkit_mask_repeat Css.Repeat_y; Css.mask_repeat Css.Repeat_y ] (* mask-clip and mask-origin utilities. Tailwind writes a [-webkit-] twin for every box, but WebKit's own grammar only has the three CSS boxes: [fill-box], [stroke-box], [view-box] and [no-clip] are dropped by every browser on the prefixed property, and [Css.webkit_mask_box] has no constructor for them, so those utilities carry the unprefixed declaration alone. *) let mask_clip_border = style [ Css.webkit_mask_clip Border_box; Css.mask_clip Border_box ] let mask_clip_padding = style [ Css.webkit_mask_clip Padding_box; Css.mask_clip Padding_box ] let mask_clip_content = style [ Css.webkit_mask_clip Content_box; Css.mask_clip Content_box ] let mask_clip_fill = style [ Css.mask_clip Fill_box ] let mask_clip_stroke = style [ Css.mask_clip Stroke_box ] let mask_clip_view = style [ Css.mask_clip View_box ] let mask_no_clip = style [ Css.mask_clip Css.No_clip ] let mask_origin_border = style [ Css.webkit_mask_origin Border_box; Css.mask_origin Border_box ] let mask_origin_padding = style [ Css.webkit_mask_origin Padding_box; Css.mask_origin Padding_box ] let mask_origin_content = style [ Css.webkit_mask_origin Content_box; Css.mask_origin Content_box ] let mask_origin_fill = style [ Css.mask_origin Fill_box ] let mask_origin_stroke = style [ Css.mask_origin Stroke_box ] let mask_origin_view = style [ Css.mask_origin View_box ] (* Bracket notation helpers *) (* [mask-size-[...]], [mask-[size:...]] and [mask-[length:...]] take any CSS length, so a token is read with the value parser rather than a hand-picked unit table. *) let parse_bracket_len s = Parse.arbitrary_length s let parse_bracket_size inner = let parts = String.split_on_char '_' inner |> List.filter (fun s -> s <> "") in match parts with | [ w; h ] -> ( match (parse_bracket_len w, parse_bracket_len h) with | Some wl, Some hl -> Some [ Css.webkit_mask_size (Size (wl, hl)); Css.mask_size (Size (wl, hl)); ] | _ -> None) | [ v ] -> Option.map (fun l -> let size : Css.background_size = Length l in [ Css.webkit_mask_size size; Css.mask_size size ]) (parse_bracket_len v) | _ -> None (* A bracket mask-position: the whole [<position>] grammar, one position per mask layer, comma-separated. [None] means the bracket is not a position, which [of_class] rejects: [mask-[position:top]] used to fall through the hand-rolled reading to a plausible-looking [center]. *) let parse_bracket_position inner : Css.position_value list option = let one entry : Css.position_value option = let cursor = Cascade.Cursor.of_string (Parse.decode_underscores entry) in match Cascade.Cursor.try_parse_full_err Css.Properties.read_position_value cursor with | Ok pos -> Some pos | Error _ -> None in let entries = String.split_on_char ',' inner |> List.map String.trim in let positions = List.map one entries in if List.exists Option.is_none positions then None else Some (List.filter_map Fun.id positions) let mask_position_style positions = style [ Css.webkit_mask_position positions; Css.mask_position positions ] let to_style _theme = function | No_mask -> mask_none | Add -> mask_add | Exclude -> mask_exclude | Intersect -> mask_intersect | Subtract -> mask_subtract | Alpha -> mask_alpha | Luminance -> mask_luminance | Match -> mask_match | Type_alpha -> mask_type_alpha | Type_luminance -> mask_type_luminance | Auto -> mask_auto | Contain -> mask_contain | Cover -> mask_cover | Position pos -> mask_position' pos | No_repeat -> mask_no_repeat' | Repeat -> mask_repeat' | Repeat_round -> mask_repeat_round' | Repeat_space -> mask_repeat_space' | Repeat_x -> mask_repeat_x' | Repeat_y -> mask_repeat_y' | Clip_border -> mask_clip_border | Clip_padding -> mask_clip_padding | Clip_content -> mask_clip_content | Clip_fill -> mask_clip_fill | Clip_stroke -> mask_clip_stroke | Clip_view -> mask_clip_view | No_clip -> mask_no_clip | Origin_border -> mask_origin_border | Origin_padding -> mask_origin_padding | Origin_content -> mask_origin_content | Origin_fill -> mask_origin_fill | Origin_stroke -> mask_origin_stroke | Origin_view -> mask_origin_view (* Bracket notation *) | Bracket_contain -> style [ Css.webkit_mask_size Css.Contain; Css.mask_size Css.Contain ] | Bracket_cover -> style [ Css.webkit_mask_size Css.Cover; Css.mask_size Css.Cover ] | Bracket_size inner -> ( match parse_bracket_size inner with | Some decls -> style decls | None -> style [ Css.webkit_mask_size Css.Auto; Css.mask_size Css.Auto ]) | Bracket_length inner -> ( match parse_bracket_size inner with | Some decls -> style decls | None -> style [ Css.webkit_mask_size Css.Auto; Css.mask_size Css.Auto ]) | Bracket_position (_, positions) -> mask_position_style positions | Bracket_typed_position (_, positions) -> mask_position_style positions (* A hint says how to read the value written after it; only a var() reference there names a custom property. *) | (Bracket_image_var v | Bracket_url_var v) when not (Parse.is_var v) -> ( match Css.parse_background_image (Parse.decode_underscores v) with | Some (img :: _) -> style [ Css.webkit_mask_image img; Css.mask_image img ] | _ -> ( match Parse.url_token (Parse.decode_arbitrary_value v) with | Some url -> style [ Css.webkit_mask_image (Url url); Css.mask_image (Url url) ] | None -> style [])) | Bracket_image_var v -> let bare = Parse.extract_var_name v in let var_ref : Css.background_image Css.var = Var.bracket bare in style [ Css.webkit_mask_image (Var var_ref); Css.webkit_mask_image (Var var_ref); Css.mask_image (Var var_ref); ] (* The whole [url()] is kept, so cascade reads the token rather than masks slicing the file name out of it: the quotes are the tokeniser's, and an escape in it stands for one character of the URL. [of_class] refuses a value the token reader will not take, so [None] names nothing. *) | Bracket_url v -> ( match Parse.url_token (Parse.decode_arbitrary_value v) with | Some url -> style [ Css.webkit_mask_image (Url url); Css.mask_image (Url url) ] | None -> style []) | Bracket_url_var v -> let bare = Parse.extract_var_name v in let var_ref : Css.background_image Css.var = Var.bracket bare in style [ Css.webkit_mask_image (Var var_ref); Css.webkit_mask_image (Var var_ref); Css.mask_image (Var var_ref); ] | Bracket_var v -> let bare = Parse.extract_var_name v in let var_ref : Css.background_image Css.var = Var.bracket bare in style [ Css.webkit_mask_image (Var var_ref); Css.webkit_mask_image (Var var_ref); Css.mask_image (Var var_ref); ] | Bracket_image v -> ( match Css.parse_background_image (Parse.decode_underscores v) with | Some (img :: _) -> style [ Css.webkit_mask_image img; Css.mask_image img ] | _ -> invalid_arg ("mask-[" ^ v ^ "]: not a valid background-image value") ) (* Sub-property bracket notation *) | Position_bracket (_, positions) -> mask_position_style positions | Position_bracket_var v -> let bare = Parse.extract_var_name v in let var_ref : Css.position_value Css.var = Var.bracket bare in style [ Css.webkit_mask_position [ Var var_ref ]; Css.webkit_mask_position [ Var var_ref ]; Css.mask_position [ Var var_ref ]; ] | Size_bracket inner -> ( match parse_bracket_size inner with | Some decls -> style decls | None -> style [ Css.webkit_mask_size Css.Auto; Css.mask_size Css.Auto ]) | Size_bracket_var v -> let bare = Parse.extract_var_name v in let var_ref : Css.background_size Css.var = Var.bracket bare in style [ Css.webkit_mask_size (Var var_ref); Css.webkit_mask_size (Var var_ref); Css.mask_size (Var var_ref); ] | Bracket_opaque { longhand; value; _ } -> style (List.filter_map (fun property -> Parse.opaque_declaration property value) (Longhand.properties longhand)) (* Tailwind sorts by the property a utility sets, at the rank its property table gives it: mask-image (209), then mask-composite (257) through mask-origin (264). Utilities that set the same property share a slot, where the class name breaks the tie. *) let property_rank = function | Bracket_image_var _ | Bracket_image _ | Bracket_url _ | Bracket_url_var _ | Bracket_var _ | No_mask -> 209 | Add | Exclude | Intersect | Subtract -> 257 | Alpha | Luminance | Match -> 258 | Type_alpha | Type_luminance -> 259 | Bracket_contain | Bracket_cover | Bracket_length _ | Bracket_size _ | Auto | Contain | Cover | Size_bracket _ | Size_bracket_var _ -> 260 | Clip_border | Clip_content | Clip_fill | Clip_padding | Clip_stroke | Clip_view | No_clip -> 261 | Bracket_position _ | Bracket_typed_position _ | Position _ | Position_bracket _ | Position_bracket_var _ -> 262 | No_repeat | Repeat | Repeat_round | Repeat_space | Repeat_x | Repeat_y -> 263 | Origin_border | Origin_content | Origin_fill | Origin_padding | Origin_stroke | Origin_view -> 264 | Bracket_opaque { longhand; _ } -> Longhand.rank longhand (* Each of these writes one property and stops there, so it closes that property's slot: the mask-gradient utilities that write mask-image and carry on sort inside mask-image's, and the background sizing utilities that share this priority take the slots between the two families. *) let suborder t = Utility.Property_order.last (property_rank t) (* [mask-[<image>]] takes any background-image value, so what makes one is whether the value parser accepts it, not which gradient function it names. *) let is_image_value inner = match Css.parse_background_image (Parse.decode_underscores inner) with | Some (_ :: _) -> true | _ -> false (* What the value of an [image:]/[url:] hint may be: a var() reference, a [url()] token, or a literal image such as a gradient. *) let is_mask_image_value v = Parse.is_var v || is_image_value v || Parse.url_token (Parse.decode_arbitrary_value v) <> None (* A bracket no reader takes is still a utility: it is written into [longhand] as the author spelled it, less the data-type hint that chose the longhand. Take the whole bracket here and let [arbitrary_declaration_value] peel it, so the hint comes off once however this family routed the class. A value that would end the declaration or swallow what follows it is not one, and neither is a bracket opening with a [:]. *) let opaque spelling longhand inner = match Parse.arbitrary_declaration_value inner with | Some value -> Ok (Bracket_opaque { spelling; longhand; value }) | None -> Error (`Msg ("Unknown mask bracket value: " ^ inner)) (* Tailwind reads a bracket holding a math function as a length, and a length is a position component, so such a value goes to mask-position however the rest of it reads: [mask-[foo_calc(1+2)]] is a position where [mask-[foo_10px]] is an image. *) let holds_math_function inner = let len = String.length inner in let is_name_char c = (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9') || c = '-' in let rec name_start i = if i > 0 && is_name_char inner.[i - 1] then name_start (i - 1) else i in let rec scan i = i < len && ((inner.[i] = '(' && let s = name_start i in Css.Properties.is_math_function (String.lowercase_ascii (String.sub inner s (i - s)))) || scan (i + 1)) in scan 0 let of_class _theme class_name = let parts = Parse.split_class class_name in match parts with | [ "mask"; "none" ] -> Ok No_mask | [ "mask"; "add" ] -> Ok Add | [ "mask"; "exclude" ] -> Ok Exclude | [ "mask"; "intersect" ] -> Ok Intersect | [ "mask"; "subtract" ] -> Ok Subtract | [ "mask"; "alpha" ] -> Ok Alpha | [ "mask"; "luminance" ] -> Ok Luminance | [ "mask"; "match" ] -> Ok Match | [ "mask"; "type"; "alpha" ] -> Ok Type_alpha | [ "mask"; "type"; "luminance" ] -> Ok Type_luminance | [ "mask"; "auto" ] -> Ok Auto | [ "mask"; "contain" ] -> Ok Contain | [ "mask"; "cover" ] -> Ok Cover (* mask-position *) | [ "mask"; "bottom" ] -> Ok (Position Keyword.Bottom) | [ "mask"; "bottom"; "left" ] -> Ok (Position Keyword.Bottom_left) | [ "mask"; "bottom"; "right" ] -> Ok (Position Keyword.Bottom_right) | [ "mask"; "center" ] -> Ok (Position Keyword.Center) | [ "mask"; "left" ] -> Ok (Position Keyword.Left) | [ "mask"; "right" ] -> Ok (Position Keyword.Right) | [ "mask"; "top" ] -> Ok (Position Keyword.Top) | [ "mask"; "top"; "left" ] -> Ok (Position Keyword.Top_left) | [ "mask"; "top"; "right" ] -> Ok (Position Keyword.Top_right) (* mask-repeat *) | [ "mask"; "no"; "repeat" ] -> Ok No_repeat | [ "mask"; "repeat" ] -> Ok Repeat | [ "mask"; "repeat"; "round" ] -> Ok Repeat_round | [ "mask"; "repeat"; "space" ] -> Ok Repeat_space | [ "mask"; "repeat"; "x" ] -> Ok Repeat_x | [ "mask"; "repeat"; "y" ] -> Ok Repeat_y (* mask-clip *) | [ "mask"; "clip"; "border" ] -> Ok Clip_border | [ "mask"; "clip"; "padding" ] -> Ok Clip_padding | [ "mask"; "clip"; "content" ] -> Ok Clip_content | [ "mask"; "clip"; "fill" ] -> Ok Clip_fill | [ "mask"; "clip"; "stroke" ] -> Ok Clip_stroke | [ "mask"; "clip"; "view" ] -> Ok Clip_view | [ "mask"; "no"; "clip" ] -> Ok No_clip (* mask-origin *) | [ "mask"; "origin"; "border" ] -> Ok Origin_border | [ "mask"; "origin"; "padding" ] -> Ok Origin_padding | [ "mask"; "origin"; "content" ] -> Ok Origin_content | [ "mask"; "origin"; "fill" ] -> Ok Origin_fill | [ "mask"; "origin"; "stroke" ] -> Ok Origin_stroke | [ "mask"; "origin"; "view" ] -> Ok Origin_view (* Sub-property bracket notation: mask-position-[...], mask-size-[...] *) | [ "mask"; "position"; bracket ] when Parse.is_bracket_value bracket -> ( let inner = Parse.bracket_inner bracket in (* This class names its longhand outright, so a hint in front of the value says nothing more than where the value starts. *) match Parse.data_type_hint inner with | Some _ -> opaque class_name Longhand.Position inner | None -> ( if Parse.is_var inner then Ok (Position_bracket_var inner) else match parse_bracket_position inner with | Some positions -> Ok (Position_bracket (inner, positions)) | None -> opaque class_name Longhand.Position inner)) | [ "mask"; "size"; bracket ] when Parse.is_bracket_value bracket -> ( let inner = Parse.bracket_inner bracket in match Parse.data_type_hint inner with | Some _ -> opaque class_name Longhand.Size inner | None -> if Parse.is_var inner then Ok (Size_bracket_var inner) else if parse_bracket_size inner = None then opaque class_name Longhand.Size inner else Ok (Size_bracket inner)) (* Bracket notation: mask-[...] *) | [ "mask"; bracket ] when Parse.is_bracket_value bracket -> ( let inner = Parse.bracket_inner bracket in (* A hint with nothing after it names no value: it is read below as a hint Tailwind does not know. *) let hint = Option.bind (Parse.data_type_hint inner) (fun (h, v) -> if v = "" then Option.none else Option.some (h, v)) in match (inner, hint) with | "contain", _ -> Ok Bracket_contain | "cover", _ -> Ok Bracket_cover | _, Some ("length", v) -> (* The [length:] hint forces a mask-size, and says nothing about whether the value is one: a size the grammar cannot take is written out as the author spelled it. *) if parse_bracket_size v = None then opaque class_name Longhand.Size inner else Ok (Bracket_length v) | _, Some ("size", v) -> if parse_bracket_size v = None then opaque class_name Longhand.Size inner else Ok (Bracket_size v) | _, Some ("position", v) -> ( (* The [position:] hint forces a mask-position the same way. *) match parse_bracket_position v with | Some positions -> Ok (Bracket_typed_position (v, positions)) | None -> opaque class_name Longhand.Position inner) (* An [image:]/[url:] hint says how to read the value written after it; only a var() reference there names a custom property. *) | _, Some ("image", v) -> if is_mask_image_value v then Ok (Bracket_image_var v) else opaque class_name Longhand.Image inner | _, Some ("url", v) -> if is_mask_image_value v then Ok (Bracket_url_var v) else opaque class_name Longhand.Image inner (* Before the [url(...)] reading below, which takes one whole token and so has no answer for the comma of a layer list. *) | _ when is_image_value inner -> Ok (Bracket_image inner) | _ when String.starts_with ~prefix:"url(" inner -> ( match Parse.url_token (Parse.decode_arbitrary_value inner) with | Some _ -> Ok (Bracket_url inner) | None -> opaque class_name Longhand.Image inner) | _ when Parse.is_var inner -> Ok (Bracket_var inner) (* A hint Tailwind does not know here settles the longhand all the same: it takes the last resort, and nothing is read from the value that follows it. The name is a run of [a-z] and [-], so [10px:2em] and [FOO:2em] carry no hint and are values whole. *) | _ when Parse.data_type_hint inner <> None -> opaque class_name Longhand.Image inner | _ -> ( match parse_bracket_position inner with | Some positions -> Ok (Bracket_position (inner, positions)) | None -> let longhand = if holds_math_function inner then Longhand.Position else Longhand.Image in opaque class_name longhand inner)) | _ -> Error (`Msg "Not a mask utility") let to_class = function | No_mask -> "mask-none" | Add -> "mask-add" | Exclude -> "mask-exclude" | Intersect -> "mask-intersect" | Subtract -> "mask-subtract" | Alpha -> "mask-alpha" | Luminance -> "mask-luminance" | Match -> "mask-match" | Type_alpha -> "mask-type-alpha" | Type_luminance -> "mask-type-luminance" | Auto -> "mask-auto" | Contain -> "mask-contain" | Cover -> "mask-cover" | Position Keyword.Bottom -> "mask-bottom" | Position Keyword.Bottom_left -> "mask-bottom-left" | Position Keyword.Bottom_right -> "mask-bottom-right" | Position Keyword.Center -> "mask-center" | Position Keyword.Left -> "mask-left" | Position Keyword.Right -> "mask-right" | Position Keyword.Top -> "mask-top" | Position Keyword.Top_left -> "mask-top-left" | Position Keyword.Top_right -> "mask-top-right" | No_repeat -> "mask-no-repeat" | Repeat -> "mask-repeat" | Repeat_round -> "mask-repeat-round" | Repeat_space -> "mask-repeat-space" | Repeat_x -> "mask-repeat-x" | Repeat_y -> "mask-repeat-y" | Clip_border -> "mask-clip-border" | Clip_padding -> "mask-clip-padding" | Clip_content -> "mask-clip-content" | Clip_fill -> "mask-clip-fill" | Clip_stroke -> "mask-clip-stroke" | Clip_view -> "mask-clip-view" | No_clip -> "mask-no-clip" | Origin_border -> "mask-origin-border" | Origin_padding -> "mask-origin-padding" | Origin_content -> "mask-origin-content" | Origin_fill -> "mask-origin-fill" | Origin_stroke -> "mask-origin-stroke" | Origin_view -> "mask-origin-view" | Bracket_contain -> "mask-[contain]" | Bracket_cover -> "mask-[cover]" | Bracket_size v -> "mask-[size:" ^ v ^ "]" | Bracket_length v -> "mask-[length:" ^ v ^ "]" | Bracket_position (v, _) -> "mask-[" ^ v ^ "]" | Bracket_typed_position (v, _) -> "mask-[position:" ^ v ^ "]" | Bracket_image_var v -> "mask-[image:" ^ v ^ "]" | Bracket_url v -> "mask-[" ^ v ^ "]" | Bracket_url_var v -> "mask-[url:" ^ v ^ "]" | Bracket_var v -> "mask-[" ^ v ^ "]" | Bracket_image v -> "mask-[" ^ v ^ "]" | Position_bracket (v, _) -> "mask-position-[" ^ v ^ "]" | Position_bracket_var v -> "mask-position-[" ^ v ^ "]" | Size_bracket v -> "mask-size-[" ^ v ^ "]" | Size_bracket_var v -> "mask-size-[" ^ v ^ "]" | Bracket_opaque { spelling; _ } -> spelling let examples = [ No_mask; Clip_border; Origin_border; Repeat; Type_alpha; Add; Alpha ] end open Handler module Utility_factory = Utility.Make (Handler) let utility = Utility_factory.v let mask_none = utility No_mask let mask_add = utility Add let mask_exclude = utility Exclude let mask_intersect = utility Intersect let mask_subtract = utility Subtract let mask_alpha = utility Alpha let mask_luminance = utility Luminance let mask_match = utility Match let mask_type_alpha = utility Type_alpha let mask_type_luminance = utility Type_luminance let mask_auto = utility Auto let mask_contain = utility Contain let mask_cover = utility Cover let mask_bottom = utility (Position Keyword.Bottom) let mask_bottom_left = utility (Position Keyword.Bottom_left) let mask_bottom_right = utility (Position Keyword.Bottom_right) let mask_center = utility (Position Keyword.Center) let mask_left = utility (Position Keyword.Left) let mask_right = utility (Position Keyword.Right) let mask_top = utility (Position Keyword.Top) let mask_top_left = utility (Position Keyword.Top_left) let mask_top_right = utility (Position Keyword.Top_right) let mask_no_repeat = utility No_repeat let mask_repeat = utility Repeat let mask_repeat_round = utility Repeat_round let mask_repeat_space = utility Repeat_space let mask_repeat_x = utility Repeat_x let mask_repeat_y = utility Repeat_y let mask_clip_border = utility Clip_border let mask_clip_padding = utility Clip_padding let mask_clip_content = utility Clip_content let mask_clip_fill = utility Clip_fill let mask_clip_stroke = utility Clip_stroke let mask_clip_view = utility Clip_view let mask_no_clip = utility No_clip let mask_origin_border = utility Origin_border let mask_origin_padding = utility Origin_padding let mask_origin_content = utility Origin_content let mask_origin_fill = utility Origin_fill let mask_origin_stroke = utility Origin_stroke let mask_origin_view = utility Origin_view
sectionYPositions = computeSectionYPositions($el), 10)"
x-init="setTimeout(() => sectionYPositions = computeSectionYPositions($el), 10)"
>