hypersig_style/
pattern.rs1use crate::PseudoElement;
18use crate::style::Style;
19use crate::value::{
20 AlignItems, BorderTopStyle, Color, Display, FlexDirection, FlexWrap, Gap, JustifyContent,
21 Length, MarginInline, MaxWidth, Overflow, PaddingInline, Position, WhiteSpace, pct, px, quoted,
22 raw,
23};
24
25#[must_use]
27pub fn stack(gap: impl Into<Gap>) -> Style {
28 Style::new()
29 .display(Display::Flex)
30 .flex_direction(FlexDirection::Column)
31 .gap(gap)
32}
33
34#[must_use]
36pub fn vstack(gap: impl Into<Gap>) -> Style {
37 stack(gap).align_items(AlignItems::Center)
38}
39
40#[must_use]
42pub fn hstack(gap: impl Into<Gap>) -> Style {
43 Style::new()
44 .display(Display::Flex)
45 .flex_direction(FlexDirection::Row)
46 .align_items(AlignItems::Center)
47 .gap(gap)
48}
49
50#[must_use]
52pub fn wrap(gap: impl Into<Gap>) -> Style {
53 Style::new()
54 .display(Display::Flex)
55 .flex_wrap(FlexWrap::Wrap)
56 .gap(gap)
57}
58
59#[must_use]
61pub fn center() -> Style {
62 Style::new()
63 .display(Display::Flex)
64 .align_items(AlignItems::Center)
65 .justify_content(JustifyContent::Center)
66}
67
68#[must_use]
70pub fn spacer() -> Style {
71 Style::new().flex_grow(1).flex_shrink(1).flex_basis(px(0))
72}
73
74#[must_use]
79pub fn grid(columns: u16, gap: impl Into<Gap>) -> Style {
80 Style::new()
81 .display(Display::Grid)
82 .grid_template_columns(raw(format!("repeat({columns}, minmax(0, 1fr))")))
83 .gap(gap)
84}
85
86#[must_use]
88pub fn grid_item(columns: u16) -> Style {
89 Style::new().grid_column(raw(format!("span {columns} / span {columns}")))
90}
91
92#[must_use]
94pub fn container(max: impl Into<MaxWidth>, padding: impl Into<PaddingInline>) -> Style {
95 Style::new()
96 .max_width(max)
97 .margin_inline(MarginInline::Auto)
98 .padding_inline(padding)
99}
100
101#[must_use]
103pub fn square(size: Length) -> Style {
104 center().width(size.clone()).height(size).flex_shrink(0)
105}
106
107#[must_use]
109pub fn circle(size: Length) -> Style {
110 square(size).border_radius(pct(50))
111}
112
113#[must_use]
116pub fn aspect_ratio(ratio: f64) -> Style {
117 Style::new()
118 .position(Position::Relative)
119 .aspect_ratio(ratio)
120 .overflow(Overflow::Hidden)
121}
122
123#[must_use]
125pub fn divider(width: Length, color: Color) -> Style {
126 Style::new()
127 .border_top_width(width)
128 .border_top_style(BorderTopStyle::Solid)
129 .border_top_color(color)
130}
131
132#[must_use]
135pub fn visually_hidden() -> Style {
136 Style::new()
137 .position(Position::Absolute)
138 .width(px(1))
139 .height(px(1))
140 .padding(px(0))
141 .margin(px(-1))
142 .overflow(Overflow::Hidden)
143 .clip_path(raw("inset(50%)"))
144 .white_space(WhiteSpace::Nowrap)
145 .border_width(px(0))
146}
147
148#[must_use]
151pub fn link_overlay() -> Style {
152 Style::new().pseudo(
153 PseudoElement::Before,
154 Style::new()
155 .content(quoted(""))
156 .position(Position::Absolute)
157 .inset(px(0)),
158 )
159}
160
161#[cfg(test)]
162mod tests {
163 use super::{circle, grid, link_overlay, stack};
164 use crate::Sheet;
165 use crate::value::rem;
166
167 #[test]
168 fn writes_the_declarations_of_a_pattern() {
169 assert_eq!(
170 stack(rem(1)).class_names().collect::<Vec<_>>(),
171 ["display_flex", "flex-direction_column", "gap_1rem"]
172 );
173 assert!(
174 circle(rem(2))
175 .class_names()
176 .any(|name| name == "border-radius_50%")
177 );
178 let mut sheet = Sheet::new();
179 sheet.add(&grid(3, rem(1)));
180 assert!(
181 sheet
182 .to_css()
183 .contains("{grid-template-columns:repeat(3, minmax(0, 1fr))}")
184 );
185 }
186
187 #[test]
188 fn puts_the_overlay_on_a_pseudo_element() {
189 let mut sheet = Sheet::new();
190 sheet.add(&link_overlay());
191 let css = sheet.to_css();
192 assert!(css.contains("::before{content:\"\"}"));
193 assert!(css.contains("::before{inset:0}"));
194 }
195}