tailwind_fuse/core/merge/mod.rs
1pub(crate) mod config;
2pub(crate) mod get_collision_id;
3pub(crate) mod get_collisions;
4pub(crate) mod merge_impl;
5pub(crate) mod validators;
6
7pub use config::*;
8pub use merge_impl::tw_merge_override;
9
10/// Merges all the Tailwind classes, resolving conflicts.
11///
12/// Items can be anything that implements [`crate::AsTailwindClass`].
13///
14/// If you DON'T want to handle conflicts use [`crate::tw_join!`].
15///
16/// If you want to set global options use [`crate::merge::set_merge_options`].
17///
18/// If you want a custom type to be used with this macro, implement the [`crate::MaybeIntoTailwindClass`] trait.
19#[macro_export]
20macro_rules! tw_merge {
21 ($($item:expr),+ $(,)?) => {{
22 let joined = $crate::tw_join!($($item),+);
23 $crate::merge::tw_merge(joined.as_str())
24 }};
25}
26
27/// Merges all the Tailwind classes in the string, resolving conflicts.
28///
29/// If you need custom options use [`tw_merge_options`].
30#[inline]
31pub fn tw_merge(class: impl AsRef<str>) -> String {
32 tw_merge_slice_options(&[class.as_ref()], Default::default())
33}
34
35/// Merges all the Tailwind classes in the provided strings, resolving conflicts.
36/// Useful to avoid collecting all the strings into a single string.
37///
38/// If you need custom options use [`tw_merge_slice_options`].
39#[inline]
40pub fn tw_merge_slice(class: &[&str]) -> String {
41 tw_merge_slice_options(class, Default::default())
42}
43
44/// Merges all the Tailwind classes, resolving conflicts, with the provided options.
45///
46/// ## Example: With Tailwind Prefix
47///
48/// ```
49/// # use tailwind_fuse::merge::*;
50/// const OPTIONS: MergeOptions = MergeOptions {
51/// prefix: "tw-",
52/// separator: ":",
53/// };
54///
55/// pub fn my_custom_tw_merge(class: impl AsRef<str>) -> String {
56/// tw_merge_options(class, OPTIONS)
57/// }
58/// ```
59#[inline]
60pub fn tw_merge_options(class: impl AsRef<str>, options: MergeOptions) -> String {
61 merge_impl::tw_merge_override(
62 &[class.as_ref()],
63 options,
64 |_: &[&str], _: Option<&str>| None,
65 |_: &str| None,
66 )
67}
68
69/// Merges all the Tailwind classes in the provided strings, resolving conflicts.
70/// Useful to avoid collecting all the strings into a single string.
71///
72/// If you don't need custom options use [`tw_merge_slice`].
73///
74/// ## Example: With Tailwind Prefix
75///
76/// ```
77/// # use tailwind_fuse::merge::*;
78/// const OPTIONS: MergeOptions = MergeOptions {
79/// prefix: "tw-",
80/// separator: ":",
81/// };
82///
83/// pub fn my_custom_tw_merge(class: &[&str]) -> String {
84/// tw_merge_slice_options(class, OPTIONS)
85/// }
86/// ```
87#[inline]
88pub fn tw_merge_slice_options(class: &[&str], options: MergeOptions) -> String {
89 merge_impl::tw_merge_override(
90 class,
91 options,
92 |_: &[&str], _: Option<&str>| None,
93 |_: &str| None,
94 )
95}
96
97/// Return a ConflictId for a given Tailwind Class.
98pub trait CollisionIdFn {
99 /// elements: parts of the Tailwind class separated by `-`.
100 ///
101 /// (e.g. `bg-red-500` would be `["bg", "red", "500"]`)
102 ///
103 /// arbitrary: the arbitrary value at the end of the Tailwind class
104 ///
105 /// <https://tailwindcss.com/docs/adding-custom-styles#using-arbitrary-values>
106 fn apply(&self, elements: &[&str], arbitrary: Option<&str>) -> Option<&'static str>;
107}
108
109impl<F> CollisionIdFn for F
110where
111 F: Fn(&[&str], Option<&str>) -> Option<&'static str> + 'static,
112{
113 fn apply(&self, elements: &[&str], arbitrary: Option<&str>) -> Option<&'static str> {
114 self(elements, arbitrary)
115 }
116}
117
118/// Return list of CollisionIds that collide with the given CollisionId.
119///
120/// The list does not need to contain the given CollisionId.
121///
122/// e.g. "flex-row" should probably collide with "flex-col"
123pub trait GetCollisionsFn {
124 /// Return list of CollisionIds that collide with the given CollisionId.
125 fn apply(&self, collision_id: &str) -> Option<Vec<&'static str>>;
126}
127
128impl<F> GetCollisionsFn for F
129where
130 F: Fn(&str) -> Option<Vec<&'static str>>,
131{
132 fn apply(&self, collision_id: &str) -> Option<Vec<&'static str>> {
133 self(collision_id)
134 }
135}