Fix clippy lints (2024-10-10) (#720)
1//! Style types for CSS Grid layout
2use super::{AlignContent, AlignItems, AlignSelf, CoreStyle, JustifyContent, LengthPercentage, Style};
3use crate::compute::grid::{GridCoordinate, GridLine, OriginZeroLine};
4use crate::geometry::{AbsoluteAxis, AbstractAxis, Line, MinMax, Size};
5use crate::style_helpers::*;
6use crate::util::sys::GridTrackVec;
7use core::borrow::Borrow;
8use core::cmp::{max, min};
9use core::convert::Infallible;
10
11/// The set of styles required for a CSS Grid container
12pub trait GridContainerStyle: CoreStyle {
13 /// The type returned by grid_template_rows and grid_template_columns
14 type TemplateTrackList<'a>: Borrow<[TrackSizingFunction]>
15 where
16 Self: 'a;
17 /// The type returned by grid_auto_rows and grid_auto_columns
18 type AutoTrackList<'a>: Borrow<[NonRepeatedTrackSizingFunction]>
19 where
20 Self: 'a;
21
22 // FIXME: re-add default implemenations for grid_{template,auto}_{rows,columns} once the
23 // associated_type_defaults feature (https://github.com/rust-lang/rust/issues/29661) is stabilised.
24
25 /// Defines the track sizing functions (heights) of the grid rows
26 fn grid_template_rows(&self) -> Self::TemplateTrackList<'_>;
27 /// Defines the track sizing functions (widths) of the grid columns
28 fn grid_template_columns(&self) -> Self::TemplateTrackList<'_>;
29 /// Defines the size of implicitly created rows
30 fn grid_auto_rows(&self) -> Self::AutoTrackList<'_>;
31 /// Defined the size of implicitly created columns
32 fn grid_auto_columns(&self) -> Self::AutoTrackList<'_>;
33
34 /// Controls how items get placed into the grid for auto-placed items
35 #[inline(always)]
36 fn grid_auto_flow(&self) -> GridAutoFlow {
37 Style::DEFAULT.grid_auto_flow
38 }
39
40 /// How large should the gaps between items in a grid or flex container be?
41 #[inline(always)]
42 fn gap(&self) -> Size<LengthPercentage> {
43 Style::DEFAULT.gap
44 }
45
46 // Alignment properties
47
48 /// How should content contained within this item be aligned in the cross/block axis
49 #[inline(always)]
50 fn align_content(&self) -> Option<AlignContent> {
51 Style::DEFAULT.align_content
52 }
53 /// How should contained within this item be aligned in the main/inline axis
54 #[inline(always)]
55 fn justify_content(&self) -> Option<JustifyContent> {
56 Style::DEFAULT.justify_content
57 }
58 /// How this node's children aligned in the cross/block axis?
59 #[inline(always)]
60 fn align_items(&self) -> Option<AlignItems> {
61 Style::DEFAULT.align_items
62 }
63 /// How this node's children should be aligned in the inline axis
64 #[inline(always)]
65 fn justify_items(&self) -> Option<AlignItems> {
66 Style::DEFAULT.justify_items
67 }
68
69 /// Get a grid item's row or column placement depending on the axis passed
70 #[inline(always)]
71 fn grid_template_tracks(&self, axis: AbsoluteAxis) -> Self::TemplateTrackList<'_> {
72 match axis {
73 AbsoluteAxis::Horizontal => self.grid_template_columns(),
74 AbsoluteAxis::Vertical => self.grid_template_rows(),
75 }
76 }
77
78 /// Get a grid container's align-content or justify-content alignment depending on the axis passed
79 #[inline(always)]
80 fn grid_align_content(&self, axis: AbstractAxis) -> AlignContent {
81 match axis {
82 AbstractAxis::Inline => self.justify_content().unwrap_or(AlignContent::Stretch),
83 AbstractAxis::Block => self.align_content().unwrap_or(AlignContent::Stretch),
84 }
85 }
86}
87
88/// The set of styles required for a CSS Grid item (child of a CSS Grid container)
89pub trait GridItemStyle: CoreStyle {
90 /// Defines which row in the grid the item should start and end at
91 #[inline(always)]
92 fn grid_row(&self) -> Line<GridPlacement> {
93 Style::DEFAULT.grid_row
94 }
95 /// Defines which column in the grid the item should start and end at
96 #[inline(always)]
97 fn grid_column(&self) -> Line<GridPlacement> {
98 Style::DEFAULT.grid_column
99 }
100
101 /// How this node should be aligned in the cross/block axis
102 /// Falls back to the parents [`AlignItems`] if not set
103 #[inline(always)]
104 fn align_self(&self) -> Option<AlignSelf> {
105 Style::DEFAULT.align_self
106 }
107 /// How this node should be aligned in the inline axis
108 /// Falls back to the parents [`super::JustifyItems`] if not set
109 #[inline(always)]
110 fn justify_self(&self) -> Option<AlignSelf> {
111 Style::DEFAULT.justify_self
112 }
113
114 /// Get a grid item's row or column placement depending on the axis passed
115 #[inline(always)]
116 fn grid_placement(&self, axis: AbsoluteAxis) -> Line<GridPlacement> {
117 match axis {
118 AbsoluteAxis::Horizontal => self.grid_column(),
119 AbsoluteAxis::Vertical => self.grid_row(),
120 }
121 }
122}
123
124/// Controls whether grid items are placed row-wise or column-wise. And whether the sparse or dense packing algorithm is used.
125///
126/// The "dense" packing algorithm attempts to fill in holes earlier in the grid, if smaller items come up later. This may cause items to appear out-of-order, when doing so would fill in holes left by larger items.
127///
128/// Defaults to [`GridAutoFlow::Row`]
129///
130/// [MDN](https://developer.mozilla.org/en-US/docs/Web/CSS/grid-auto-flow)
131#[derive(Copy, Clone, PartialEq, Eq, Debug)]
132#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
133pub enum GridAutoFlow {
134 /// Items are placed by filling each row in turn, adding new rows as necessary
135 Row,
136 /// Items are placed by filling each column in turn, adding new columns as necessary.
137 Column,
138 /// Combines `Row` with the dense packing algorithm.
139 RowDense,
140 /// Combines `Column` with the dense packing algorithm.
141 ColumnDense,
142}
143
144impl Default for GridAutoFlow {
145 fn default() -> Self {
146 Self::Row
147 }
148}
149
150impl GridAutoFlow {
151 /// Whether grid auto placement uses the sparse placement algorithm or the dense placement algorithm
152 /// See: <https://developer.mozilla.org/en-US/docs/Web/CSS/grid-auto-flow#values>
153 pub fn is_dense(&self) -> bool {
154 match self {
155 Self::Row | Self::Column => false,
156 Self::RowDense | Self::ColumnDense => true,
157 }
158 }
159
160 /// Whether grid auto placement fills areas row-wise or column-wise
161 /// See: <https://developer.mozilla.org/en-US/docs/Web/CSS/grid-auto-flow#values>
162 pub fn primary_axis(&self) -> AbsoluteAxis {
163 match self {
164 Self::Row | Self::RowDense => AbsoluteAxis::Horizontal,
165 Self::Column | Self::ColumnDense => AbsoluteAxis::Vertical,
166 }
167 }
168}
169
170/// A grid line placement specification which is generic over the coordinate system that it uses to define
171/// grid line positions.
172///
173/// GenericGridPlacement<GridLine> is aliased as GridPlacement and is exposed to users of Taffy to define styles.
174/// GenericGridPlacement<OriginZeroLine> is aliased as OriginZeroGridPlacement and is used internally for placement computations.
175///
176/// See [`crate::compute::grid::type::coordinates`] for documentation on the different coordinate systems.
177#[derive(Copy, Clone, PartialEq, Eq, Debug)]
178#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
179pub enum GenericGridPlacement<LineType: GridCoordinate> {
180 /// Place item according to the auto-placement algorithm, and the parent's grid_auto_flow property
181 Auto,
182 /// Place item at specified line (column or row) index
183 Line(LineType),
184 /// Item should span specified number of tracks (columns or rows)
185 Span(u16),
186}
187
188/// A grid line placement using the normalized OriginZero coordinates to specify line positions.
189pub(crate) type OriginZeroGridPlacement = GenericGridPlacement<OriginZeroLine>;
190
191/// A grid line placement specification. Used for grid-[row/column]-[start/end]. Named tracks are not implemented.
192///
193/// Defaults to `GridPlacement::Auto`
194///
195/// [Specification](https://www.w3.org/TR/css3-grid-layout/#typedef-grid-row-start-grid-line)
196pub type GridPlacement = GenericGridPlacement<GridLine>;
197impl TaffyAuto for GridPlacement {
198 const AUTO: Self = Self::Auto;
199}
200impl TaffyGridLine for GridPlacement {
201 fn from_line_index(index: i16) -> Self {
202 GridPlacement::Line(GridLine::from(index))
203 }
204}
205impl TaffyGridLine for Line<GridPlacement> {
206 fn from_line_index(index: i16) -> Self {
207 Line { start: GridPlacement::from_line_index(index), end: GridPlacement::Auto }
208 }
209}
210impl TaffyGridSpan for GridPlacement {
211 fn from_span(span: u16) -> Self {
212 GridPlacement::Span(span)
213 }
214}
215impl TaffyGridSpan for Line<GridPlacement> {
216 fn from_span(span: u16) -> Self {
217 Line { start: GridPlacement::from_span(span), end: GridPlacement::Auto }
218 }
219}
220
221impl Default for GridPlacement {
222 fn default() -> Self {
223 Self::Auto
224 }
225}
226
227impl GridPlacement {
228 /// Apply a mapping function if the [`GridPlacement`] is a `Track`. Otherwise return `self` unmodified.
229 pub fn into_origin_zero_placement(self, explicit_track_count: u16) -> OriginZeroGridPlacement {
230 match self {
231 Self::Auto => OriginZeroGridPlacement::Auto,
232 Self::Span(span) => OriginZeroGridPlacement::Span(span),
233 // Grid line zero is an invalid index, so it gets treated as Auto
234 // See: https://developer.mozilla.org/en-US/docs/Web/CSS/grid-row-start#values
235 Self::Line(line) => match line.as_i16() {
236 0 => OriginZeroGridPlacement::Auto,
237 _ => OriginZeroGridPlacement::Line(line.into_origin_zero_line(explicit_track_count)),
238 },
239 }
240 }
241}
242
243impl<T: GridCoordinate> Line<GenericGridPlacement<T>> {
244 /// Resolves the span for an indefinite placement (a placement that does not consist of two `Track`s).
245 /// Panics if called on a definite placement
246 pub fn indefinite_span(&self) -> u16 {
247 use GenericGridPlacement as GP;
248 match (self.start, self.end) {
249 (GP::Line(_), GP::Auto) => 1,
250 (GP::Auto, GP::Line(_)) => 1,
251 (GP::Auto, GP::Auto) => 1,
252 (GP::Line(_), GP::Span(span)) => span,
253 (GP::Span(span), GP::Line(_)) => span,
254 (GP::Span(span), GP::Auto) => span,
255 (GP::Auto, GP::Span(span)) => span,
256 (GP::Span(span), GP::Span(_)) => span,
257 (GP::Line(_), GP::Line(_)) => panic!("indefinite_span should only be called on indefinite grid tracks"),
258 }
259 }
260}
261
262impl Line<GridPlacement> {
263 #[inline]
264 /// Whether the track position is definite in this axis (or the item will need auto placement)
265 /// The track position is definite if least one of the start and end positions is a NON-ZERO track index
266 /// (0 is an invalid line in GridLine coordinates, and falls back to "auto" which is indefinite)
267 pub fn is_definite(&self) -> bool {
268 match (self.start, self.end) {
269 (GenericGridPlacement::Line(line), _) if line.as_i16() != 0 => true,
270 (_, GenericGridPlacement::Line(line)) if line.as_i16() != 0 => true,
271 _ => false,
272 }
273 }
274
275 /// Apply a mapping function if the [`GridPlacement`] is a `Track`. Otherwise return `self` unmodified.
276 pub fn into_origin_zero(&self, explicit_track_count: u16) -> Line<OriginZeroGridPlacement> {
277 Line {
278 start: self.start.into_origin_zero_placement(explicit_track_count),
279 end: self.end.into_origin_zero_placement(explicit_track_count),
280 }
281 }
282}
283
284impl Line<OriginZeroGridPlacement> {
285 #[inline]
286 /// Whether the track position is definite in this axis (or the item will need auto placement)
287 /// The track position is definite if least one of the start and end positions is a track index
288 pub fn is_definite(&self) -> bool {
289 matches!((self.start, self.end), (GenericGridPlacement::Line(_), _) | (_, GenericGridPlacement::Line(_)))
290 }
291
292 /// If at least one of the of the start and end positions is a track index then the other end can be resolved
293 /// into a track index purely based on the information contained with the placement specification
294 pub fn resolve_definite_grid_lines(&self) -> Line<OriginZeroLine> {
295 use OriginZeroGridPlacement as GP;
296 match (self.start, self.end) {
297 (GP::Line(line1), GP::Line(line2)) => {
298 if line1 == line2 {
299 Line { start: line1, end: line1 + 1 }
300 } else {
301 Line { start: min(line1, line2), end: max(line1, line2) }
302 }
303 }
304 (GP::Line(line), GP::Span(span)) => Line { start: line, end: line + span },
305 (GP::Line(line), GP::Auto) => Line { start: line, end: line + 1 },
306 (GP::Span(span), GP::Line(line)) => Line { start: line - span, end: line },
307 (GP::Auto, GP::Line(line)) => Line { start: line - 1, end: line },
308 _ => panic!("resolve_definite_grid_tracks should only be called on definite grid tracks"),
309 }
310 }
311
312 /// For absolutely positioned items:
313 /// - Tracks resolve to definite tracks
314 /// - For Spans:
315 /// - If the other position is a Track, they resolve to a definite track relative to the other track
316 /// - Else resolve to None
317 /// - Auto resolves to None
318 ///
319 /// When finally positioning the item, a value of None means that the item's grid area is bounded by the grid
320 /// container's border box on that side.
321 pub fn resolve_absolutely_positioned_grid_tracks(&self) -> Line<Option<OriginZeroLine>> {
322 use OriginZeroGridPlacement as GP;
323 match (self.start, self.end) {
324 (GP::Line(track1), GP::Line(track2)) => {
325 if track1 == track2 {
326 Line { start: Some(track1), end: Some(track1 + 1) }
327 } else {
328 Line { start: Some(min(track1, track2)), end: Some(max(track1, track2)) }
329 }
330 }
331 (GP::Line(track), GP::Span(span)) => Line { start: Some(track), end: Some(track + span) },
332 (GP::Line(track), GP::Auto) => Line { start: Some(track), end: None },
333 (GP::Span(span), GP::Line(track)) => Line { start: Some(track - span), end: Some(track) },
334 (GP::Auto, GP::Line(track)) => Line { start: None, end: Some(track) },
335 _ => Line { start: None, end: None },
336 }
337 }
338
339 /// If neither of the start and end positions is a track index then the other end can be resolved
340 /// into a track index if a definite start position is supplied externally
341 pub fn resolve_indefinite_grid_tracks(&self, start: OriginZeroLine) -> Line<OriginZeroLine> {
342 use OriginZeroGridPlacement as GP;
343 match (self.start, self.end) {
344 (GP::Auto, GP::Auto) => Line { start, end: start + 1 },
345 (GP::Span(span), GP::Auto) => Line { start, end: start + span },
346 (GP::Auto, GP::Span(span)) => Line { start, end: start + span },
347 (GP::Span(span), GP::Span(_)) => Line { start, end: start + span },
348 _ => panic!("resolve_indefinite_grid_tracks should only be called on indefinite grid tracks"),
349 }
350 }
351}
352
353/// Represents the start and end points of a GridItem within a given axis
354impl Default for Line<GridPlacement> {
355 fn default() -> Self {
356 Line { start: GridPlacement::Auto, end: GridPlacement::Auto }
357 }
358}
359
360/// Maximum track sizing function
361///
362/// Specifies the maximum size of a grid track. A grid track will automatically size between it's minimum and maximum size based
363/// on the size of it's contents, the amount of available space, and the sizing constraint the grid is being size under.
364/// See <https://developer.mozilla.org/en-US/docs/Web/CSS/grid-template-columns>
365#[derive(Copy, Clone, PartialEq, Debug)]
366#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
367pub enum MaxTrackSizingFunction {
368 /// Track maximum size should be a fixed length or percentage value
369 Fixed(LengthPercentage),
370 /// Track maximum size should be content sized under a min-content constraint
371 MinContent,
372 /// Track maximum size should be content sized under a max-content constraint
373 MaxContent,
374 /// Track maximum size should be sized according to the fit-content formula
375 FitContent(LengthPercentage),
376 /// Track maximum size should be automatically sized
377 Auto,
378 /// The dimension as a fraction of the total available grid space (`fr` units in CSS)
379 /// Specified value is the numerator of the fraction. Denominator is the sum of all fraction specified in that grid dimension
380 /// Spec: <https://www.w3.org/TR/css3-grid-layout/#fr-unit>
381 Fraction(f32),
382}
383impl TaffyAuto for MaxTrackSizingFunction {
384 const AUTO: Self = Self::Auto;
385}
386impl TaffyMinContent for MaxTrackSizingFunction {
387 const MIN_CONTENT: Self = Self::MinContent;
388}
389impl TaffyMaxContent for MaxTrackSizingFunction {
390 const MAX_CONTENT: Self = Self::MaxContent;
391}
392impl TaffyFitContent for MaxTrackSizingFunction {
393 fn fit_content(argument: LengthPercentage) -> Self {
394 Self::FitContent(argument)
395 }
396}
397impl TaffyZero for MaxTrackSizingFunction {
398 const ZERO: Self = Self::Fixed(LengthPercentage::ZERO);
399}
400impl FromLength for MaxTrackSizingFunction {
401 fn from_length<Input: Into<f32> + Copy>(value: Input) -> Self {
402 Self::Fixed(LengthPercentage::from_length(value))
403 }
404}
405impl FromPercent for MaxTrackSizingFunction {
406 fn from_percent<Input: Into<f32> + Copy>(percent: Input) -> Self {
407 Self::Fixed(LengthPercentage::from_percent(percent))
408 }
409}
410impl FromFlex for MaxTrackSizingFunction {
411 fn from_flex<Input: Into<f32> + Copy>(flex: Input) -> Self {
412 Self::Fraction(flex.into())
413 }
414}
415
416impl MaxTrackSizingFunction {
417 /// Returns true if the max track sizing function is `MinContent`, `MaxContent`, `FitContent` or `Auto`, else false.
418 #[inline(always)]
419 pub fn is_intrinsic(&self) -> bool {
420 matches!(self, Self::MinContent | Self::MaxContent | Self::FitContent(_) | Self::Auto)
421 }
422
423 /// Returns true if the max track sizing function is `MaxContent`, `FitContent` or `Auto` else false.
424 /// "In all cases, treat auto and fit-content() as max-content, except where specified otherwise for fit-content()."
425 /// See: <https://www.w3.org/TR/css-grid-1/#algo-terms>
426 #[inline(always)]
427 pub fn is_max_content_alike(&self) -> bool {
428 matches!(self, Self::MaxContent | Self::FitContent(_) | Self::Auto)
429 }
430
431 /// Returns true if the max track sizing function is `Flex`, else false.
432 #[inline(always)]
433 pub fn is_flexible(&self) -> bool {
434 matches!(self, Self::Fraction(_))
435 }
436
437 /// Returns fixed point values directly. Attempts to resolve percentage values against
438 /// the passed available_space and returns if this results in a concrete value (which it
439 /// will if the available_space is `Some`). Otherwise returns None.
440 #[inline(always)]
441 pub fn definite_value(self, parent_size: Option<f32>) -> Option<f32> {
442 use MaxTrackSizingFunction::*;
443 match self {
444 Fixed(LengthPercentage::Length(size)) => Some(size),
445 Fixed(LengthPercentage::Percent(fraction)) => parent_size.map(|size| fraction * size),
446 MinContent | MaxContent | FitContent(_) | Auto | Fraction(_) => None,
447 }
448 }
449
450 /// Resolve the maximum size of the track as defined by either:
451 /// - A fixed track sizing function
452 /// - A percentage track sizing function (with definite available space)
453 /// - A fit-content sizing function with fixed argument
454 /// - A fit-content sizing function with percentage argument (with definite available space)
455 /// All other kinds of track sizing function return None.
456 #[inline(always)]
457 pub fn definite_limit(self, parent_size: Option<f32>) -> Option<f32> {
458 use MaxTrackSizingFunction::FitContent;
459 match self {
460 FitContent(LengthPercentage::Length(size)) => Some(size),
461 FitContent(LengthPercentage::Percent(fraction)) => parent_size.map(|size| fraction * size),
462 _ => self.definite_value(parent_size),
463 }
464 }
465
466 /// Resolve percentage values against the passed parent_size, returning Some(value)
467 /// Non-percentage values always return None.
468 #[inline(always)]
469 pub fn resolved_percentage_size(self, parent_size: f32) -> Option<f32> {
470 use MaxTrackSizingFunction::*;
471 match self {
472 Fixed(LengthPercentage::Percent(fraction)) => Some(fraction * parent_size),
473 Fixed(LengthPercentage::Length(_)) | MinContent | MaxContent | FitContent(_) | Auto | Fraction(_) => None,
474 }
475 }
476
477 /// Whether the track sizing functions depends on the size of the parent node
478 #[inline(always)]
479 pub fn uses_percentage(self) -> bool {
480 use MaxTrackSizingFunction::*;
481 matches!(self, Fixed(LengthPercentage::Percent(_)) | FitContent(LengthPercentage::Percent(_)))
482 }
483}
484
485/// Minimum track sizing function
486///
487/// Specifies the minimum size of a grid track. A grid track will automatically size between it's minimum and maximum size based
488/// on the size of it's contents, the amount of available space, and the sizing constraint the grid is being size under.
489/// See <https://developer.mozilla.org/en-US/docs/Web/CSS/grid-template-columns>
490#[derive(Copy, Clone, PartialEq, Debug)]
491#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
492pub enum MinTrackSizingFunction {
493 /// Track minimum size should be a fixed length or percentage value
494 Fixed(LengthPercentage),
495 /// Track minimum size should be content sized under a min-content constraint
496 MinContent,
497 /// Track minimum size should be content sized under a max-content constraint
498 MaxContent,
499 /// Track minimum size should be automatically sized
500 Auto,
501}
502impl TaffyAuto for MinTrackSizingFunction {
503 const AUTO: Self = Self::Auto;
504}
505impl TaffyMinContent for MinTrackSizingFunction {
506 const MIN_CONTENT: Self = Self::MinContent;
507}
508impl TaffyMaxContent for MinTrackSizingFunction {
509 const MAX_CONTENT: Self = Self::MaxContent;
510}
511impl TaffyZero for MinTrackSizingFunction {
512 const ZERO: Self = Self::Fixed(LengthPercentage::ZERO);
513}
514impl FromLength for MinTrackSizingFunction {
515 fn from_length<Input: Into<f32> + Copy>(value: Input) -> Self {
516 Self::Fixed(LengthPercentage::from_length(value))
517 }
518}
519impl FromPercent for MinTrackSizingFunction {
520 fn from_percent<Input: Into<f32> + Copy>(percent: Input) -> Self {
521 Self::Fixed(LengthPercentage::from_percent(percent))
522 }
523}
524
525impl MinTrackSizingFunction {
526 /// Returns true if the min track sizing function is `MinContent`, `MaxContent` or `Auto`, else false.
527 #[inline(always)]
528 pub fn is_intrinsic(&self) -> bool {
529 matches!(self, Self::MinContent | Self::MaxContent | Self::Auto)
530 }
531
532 /// Returns fixed point values directly. Attempts to resolve percentage values against
533 /// the passed available_space and returns if this results in a concrete value (which it
534 /// will if the available_space is `Some`). Otherwise returns `None`.
535 #[inline(always)]
536 pub fn definite_value(self, parent_size: Option<f32>) -> Option<f32> {
537 use MinTrackSizingFunction::*;
538 match self {
539 Fixed(LengthPercentage::Length(size)) => Some(size),
540 Fixed(LengthPercentage::Percent(fraction)) => parent_size.map(|size| fraction * size),
541 MinContent | MaxContent | Auto => None,
542 }
543 }
544
545 /// Resolve percentage values against the passed parent_size, returning Some(value)
546 /// Non-percentage values always return None.
547 #[inline(always)]
548 pub fn resolved_percentage_size(self, parent_size: f32) -> Option<f32> {
549 use MinTrackSizingFunction::*;
550 match self {
551 Fixed(LengthPercentage::Percent(fraction)) => Some(fraction * parent_size),
552 Fixed(LengthPercentage::Length(_)) | MinContent | MaxContent | Auto => None,
553 }
554 }
555
556 /// Whether the track sizing functions depends on the size of the parent node
557 #[inline(always)]
558 pub fn uses_percentage(self) -> bool {
559 use MinTrackSizingFunction::*;
560 matches!(self, Fixed(LengthPercentage::Percent(_)))
561 }
562}
563
564/// The sizing function for a grid track (row/column)
565///
566/// May either be a MinMax variant which specifies separate values for the min-/max- track sizing functions
567/// or a scalar value which applies to both track sizing functions.
568pub type NonRepeatedTrackSizingFunction = MinMax<MinTrackSizingFunction, MaxTrackSizingFunction>;
569impl NonRepeatedTrackSizingFunction {
570 /// Extract the min track sizing function
571 pub fn min_sizing_function(&self) -> MinTrackSizingFunction {
572 self.min
573 }
574 /// Extract the max track sizing function
575 pub fn max_sizing_function(&self) -> MaxTrackSizingFunction {
576 self.max
577 }
578 /// Determine whether at least one of the components ("min" and "max") are fixed sizing function
579 pub fn has_fixed_component(&self) -> bool {
580 matches!(self.min, MinTrackSizingFunction::Fixed(_)) || matches!(self.max, MaxTrackSizingFunction::Fixed(_))
581 }
582}
583impl TaffyAuto for NonRepeatedTrackSizingFunction {
584 const AUTO: Self = Self { min: MinTrackSizingFunction::AUTO, max: MaxTrackSizingFunction::AUTO };
585}
586impl TaffyMinContent for NonRepeatedTrackSizingFunction {
587 const MIN_CONTENT: Self =
588 Self { min: MinTrackSizingFunction::MIN_CONTENT, max: MaxTrackSizingFunction::MIN_CONTENT };
589}
590impl TaffyMaxContent for NonRepeatedTrackSizingFunction {
591 const MAX_CONTENT: Self =
592 Self { min: MinTrackSizingFunction::MAX_CONTENT, max: MaxTrackSizingFunction::MAX_CONTENT };
593}
594impl TaffyFitContent for NonRepeatedTrackSizingFunction {
595 fn fit_content(argument: LengthPercentage) -> Self {
596 Self { min: MinTrackSizingFunction::AUTO, max: MaxTrackSizingFunction::FitContent(argument) }
597 }
598}
599impl TaffyZero for NonRepeatedTrackSizingFunction {
600 const ZERO: Self = Self { min: MinTrackSizingFunction::ZERO, max: MaxTrackSizingFunction::ZERO };
601}
602impl FromLength for NonRepeatedTrackSizingFunction {
603 fn from_length<Input: Into<f32> + Copy>(value: Input) -> Self {
604 Self { min: MinTrackSizingFunction::from_length(value), max: MaxTrackSizingFunction::from_length(value) }
605 }
606}
607impl FromPercent for NonRepeatedTrackSizingFunction {
608 fn from_percent<Input: Into<f32> + Copy>(percent: Input) -> Self {
609 Self { min: MinTrackSizingFunction::from_percent(percent), max: MaxTrackSizingFunction::from_percent(percent) }
610 }
611}
612impl FromFlex for NonRepeatedTrackSizingFunction {
613 fn from_flex<Input: Into<f32> + Copy>(flex: Input) -> Self {
614 Self { min: MinTrackSizingFunction::AUTO, max: MaxTrackSizingFunction::from_flex(flex) }
615 }
616}
617
618/// The first argument to a repeated track definition. This type represents the type of automatic repetition to perform.
619///
620/// See <https://www.w3.org/TR/css-grid-1/#auto-repeat> for an explanation of how auto-repeated track definitions work
621/// and the difference between AutoFit and AutoFill.
622#[derive(Clone, Copy, Debug, PartialEq, Eq)]
623#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
624pub enum GridTrackRepetition {
625 /// Auto-repeating tracks should be generated to fit the container
626 /// See: <https://developer.mozilla.org/en-US/docs/Web/CSS/repeat#auto-fill>
627 AutoFill,
628 /// Auto-repeating tracks should be generated to fit the container
629 /// See: <https://developer.mozilla.org/en-US/docs/Web/CSS/repeat#auto-fit>
630 AutoFit,
631 /// The specified tracks should be repeated exacts N times
632 Count(u16),
633}
634impl TryFrom<u16> for GridTrackRepetition {
635 type Error = Infallible;
636 fn try_from(value: u16) -> Result<Self, Infallible> {
637 Ok(Self::Count(value))
638 }
639}
640
641/// Error returned when trying to convert a string to a GridTrackRepetition and that string is not
642/// either "auto-fit" or "auto-fill"
643#[derive(Debug)]
644pub struct InvalidStringRepetitionValue;
645#[cfg(feature = "std")]
646impl std::error::Error for InvalidStringRepetitionValue {}
647impl core::fmt::Display for InvalidStringRepetitionValue {
648 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
649 f.write_str("&str can only be converted to GridTrackRepetition if it's value is 'auto-fit' or 'auto-fill'")
650 }
651}
652impl TryFrom<&str> for GridTrackRepetition {
653 type Error = InvalidStringRepetitionValue;
654 fn try_from(value: &str) -> Result<Self, InvalidStringRepetitionValue> {
655 match value {
656 "auto-fit" => Ok(Self::AutoFit),
657 "auto-fill" => Ok(Self::AutoFill),
658 _ => Err(InvalidStringRepetitionValue),
659 }
660 }
661}
662
663/// The sizing function for a grid track (row/column)
664/// See <https://developer.mozilla.org/en-US/docs/Web/CSS/grid-template-columns>
665#[derive(Clone, PartialEq, Debug)]
666#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
667pub enum TrackSizingFunction {
668 /// A single non-repeated track
669 Single(NonRepeatedTrackSizingFunction),
670 /// Automatically generate grid tracks to fit the available space using the specified definite track lengths
671 /// Only valid if every track in template (not just the repetition) has a fixed size.
672 Repeat(GridTrackRepetition, GridTrackVec<NonRepeatedTrackSizingFunction>),
673}
674impl TrackSizingFunction {
675 /// Whether the track definition is a auto-repeated fragment
676 pub fn is_auto_repetition(&self) -> bool {
677 matches!(self, Self::Repeat(GridTrackRepetition::AutoFit | GridTrackRepetition::AutoFill, _))
678 }
679}
680impl TaffyAuto for TrackSizingFunction {
681 const AUTO: Self = Self::Single(NonRepeatedTrackSizingFunction::AUTO);
682}
683impl TaffyMinContent for TrackSizingFunction {
684 const MIN_CONTENT: Self = Self::Single(NonRepeatedTrackSizingFunction::MIN_CONTENT);
685}
686impl TaffyMaxContent for TrackSizingFunction {
687 const MAX_CONTENT: Self = Self::Single(NonRepeatedTrackSizingFunction::MAX_CONTENT);
688}
689impl TaffyFitContent for TrackSizingFunction {
690 fn fit_content(argument: LengthPercentage) -> Self {
691 Self::Single(NonRepeatedTrackSizingFunction::fit_content(argument))
692 }
693}
694impl TaffyZero for TrackSizingFunction {
695 const ZERO: Self = Self::Single(NonRepeatedTrackSizingFunction::ZERO);
696}
697impl FromLength for TrackSizingFunction {
698 fn from_length<Input: Into<f32> + Copy>(value: Input) -> Self {
699 Self::Single(NonRepeatedTrackSizingFunction::from_length(value))
700 }
701}
702impl FromPercent for TrackSizingFunction {
703 fn from_percent<Input: Into<f32> + Copy>(percent: Input) -> Self {
704 Self::Single(NonRepeatedTrackSizingFunction::from_percent(percent))
705 }
706}
707impl FromFlex for TrackSizingFunction {
708 fn from_flex<Input: Into<f32> + Copy>(flex: Input) -> Self {
709 Self::Single(NonRepeatedTrackSizingFunction::from_flex(flex))
710 }
711}
712impl From<MinMax<MinTrackSizingFunction, MaxTrackSizingFunction>> for TrackSizingFunction {
713 fn from(input: MinMax<MinTrackSizingFunction, MaxTrackSizingFunction>) -> Self {
714 Self::Single(input)
715 }
716}