1use super::align::{
4 AlignContent, AlignItems, AlignSelf, ContentDistribution, ContentPosition, JustifyContent, SelfPosition,
5};
6use super::{Property, PropertyId};
7use crate::context::PropertyHandlerContext;
8use crate::declaration::{DeclarationBlock, DeclarationList};
9use crate::error::{ParserError, PrinterError};
10use crate::macros::*;
11use crate::prefixes::{is_flex_2009, Feature};
12use crate::printer::Printer;
13use crate::targets::Browsers;
14use crate::traits::{FromStandard, Parse, PropertyHandler, Shorthand, ToCss, Zero};
15use crate::values::number::{CSSInteger, CSSNumber};
16use crate::values::{
17 length::{LengthPercentage, LengthPercentageOrAuto},
18 percentage::Percentage,
19};
20use crate::vendor_prefix::VendorPrefix;
21use cssparser::*;
22
23enum_property! {
24 pub enum FlexDirection {
26 "row": Row,
28 "row-reverse": RowReverse,
30 "column": Column,
32 "column-reverse": ColumnReverse,
34 }
35}
36
37impl Default for FlexDirection {
38 fn default() -> FlexDirection {
39 FlexDirection::Row
40 }
41}
42
43enum_property! {
44 pub enum FlexWrap {
46 "nowrap": NoWrap,
48 "wrap": Wrap,
50 "wrap-reverse": WrapReverse,
52 }
53}
54
55impl Default for FlexWrap {
56 fn default() -> FlexWrap {
57 FlexWrap::NoWrap
58 }
59}
60
61impl FromStandard<FlexWrap> for FlexWrap {
62 fn from_standard(wrap: &FlexWrap) -> Option<FlexWrap> {
63 Some(wrap.clone())
64 }
65}
66
67define_shorthand! {
68 pub struct FlexFlow(VendorPrefix) {
70 direction: FlexDirection(FlexDirection, VendorPrefix),
72 wrap: FlexWrap(FlexWrap, VendorPrefix),
74 }
75}
76
77impl<'i> Parse<'i> for FlexFlow {
78 fn parse<'t>(input: &mut Parser<'i, 't>) -> Result<Self, ParseError<'i, ParserError<'i>>> {
79 let mut direction = None;
80 let mut wrap = None;
81 loop {
82 if direction.is_none() {
83 if let Ok(value) = input.try_parse(FlexDirection::parse) {
84 direction = Some(value);
85 continue;
86 }
87 }
88 if wrap.is_none() {
89 if let Ok(value) = input.try_parse(FlexWrap::parse) {
90 wrap = Some(value);
91 continue;
92 }
93 }
94 break;
95 }
96
97 Ok(FlexFlow {
98 direction: direction.unwrap_or_default(),
99 wrap: wrap.unwrap_or_default(),
100 })
101 }
102}
103
104impl ToCss for FlexFlow {
105 fn to_css<W>(&self, dest: &mut Printer<W>) -> Result<(), PrinterError>
106 where
107 W: std::fmt::Write,
108 {
109 let mut needs_space = false;
110 if self.direction != FlexDirection::default() || self.wrap == FlexWrap::default() {
111 self.direction.to_css(dest)?;
112 needs_space = true;
113 }
114
115 if self.wrap != FlexWrap::default() {
116 if needs_space {
117 dest.write_str(" ")?;
118 }
119 self.wrap.to_css(dest)?;
120 }
121
122 Ok(())
123 }
124}
125
126define_shorthand! {
127pub struct Flex(VendorPrefix) {
129 grow: FlexGrow(CSSNumber, VendorPrefix),
131 shrink: FlexShrink(CSSNumber, VendorPrefix),
133 basis: FlexBasis(LengthPercentageOrAuto, VendorPrefix),
135 }
136}
137
138impl<'i> Parse<'i> for Flex {
139 fn parse<'t>(input: &mut Parser<'i, 't>) -> Result<Self, ParseError<'i, ParserError<'i>>> {
140 if input.try_parse(|input| input.expect_ident_matching("none")).is_ok() {
141 return Ok(Flex {
142 grow: 0.0,
143 shrink: 0.0,
144 basis: LengthPercentageOrAuto::Auto,
145 });
146 }
147
148 let mut grow = None;
149 let mut shrink = None;
150 let mut basis = None;
151
152 loop {
153 if grow.is_none() {
154 if let Ok(val) = input.try_parse(CSSNumber::parse) {
155 grow = Some(val);
156 shrink = input.try_parse(CSSNumber::parse).ok();
157 continue;
158 }
159 }
160
161 if basis.is_none() {
162 if let Ok(val) = input.try_parse(LengthPercentageOrAuto::parse) {
163 basis = Some(val);
164 continue;
165 }
166 }
167
168 break;
169 }
170
171 Ok(Flex {
172 grow: grow.unwrap_or(1.0),
173 shrink: shrink.unwrap_or(1.0),
174 basis: basis.unwrap_or(LengthPercentageOrAuto::LengthPercentage(LengthPercentage::Percentage(
175 Percentage(0.0),
176 ))),
177 })
178 }
179}
180
181impl ToCss for Flex {
182 fn to_css<W>(&self, dest: &mut Printer<W>) -> Result<(), PrinterError>
183 where
184 W: std::fmt::Write,
185 {
186 if self.grow == 0.0 && self.shrink == 0.0 && self.basis == LengthPercentageOrAuto::Auto {
187 dest.write_str("none")?;
188 return Ok(());
189 }
190
191 let is_basis_zero = match &self.basis {
192 LengthPercentageOrAuto::LengthPercentage(lp) => lp.is_zero(),
193 _ => false,
194 };
195
196 if self.grow != 1.0 || self.shrink != 1.0 || is_basis_zero {
197 self.grow.to_css(dest)?;
198 if self.shrink != 1.0 {
199 dest.write_str(" ")?;
200 self.shrink.to_css(dest)?;
201 }
202 }
203
204 if !is_basis_zero {
205 if self.grow != 1.0 || self.shrink != 1.0 {
206 dest.write_str(" ")?;
207 }
208 self.basis.to_css(dest)?;
209 }
210
211 Ok(())
212 }
213}
214
215enum_property! {
218 pub enum BoxOrient {
221 "horizontal": Horizontal,
223 "vertical": Vertical,
225 "inline-axis": InlineAxis,
227 "block-axis": BlockAxis,
229 }
230}
231
232impl FlexDirection {
233 fn to_2009(&self) -> (BoxOrient, BoxDirection) {
234 match self {
235 FlexDirection::Row => (BoxOrient::Horizontal, BoxDirection::Normal),
236 FlexDirection::Column => (BoxOrient::Vertical, BoxDirection::Normal),
237 FlexDirection::RowReverse => (BoxOrient::Horizontal, BoxDirection::Reverse),
238 FlexDirection::ColumnReverse => (BoxOrient::Vertical, BoxDirection::Reverse),
239 }
240 }
241}
242
243enum_property! {
244 pub enum BoxDirection {
247 Normal,
249 Reverse,
251 }
252}
253
254enum_property! {
255 pub enum BoxAlign {
258 Start,
260 End,
262 Center,
264 Baseline,
266 Stretch,
268 }
269}
270
271impl FromStandard<AlignItems> for BoxAlign {
272 fn from_standard(align: &AlignItems) -> Option<BoxAlign> {
273 match align {
274 AlignItems::SelfPosition(None, sp) => match sp {
275 SelfPosition::Start | SelfPosition::FlexStart => Some(BoxAlign::Start),
276 SelfPosition::End | SelfPosition::FlexEnd => Some(BoxAlign::End),
277 SelfPosition::Center => Some(BoxAlign::Center),
278 _ => None,
279 },
280 AlignItems::Stretch => Some(BoxAlign::Stretch),
281 _ => None,
282 }
283 }
284}
285
286enum_property! {
287 pub enum BoxPack {
290 Start,
292 End,
294 Center,
296 Justify,
298 }
299}
300
301impl FromStandard<JustifyContent> for BoxPack {
302 fn from_standard(justify: &JustifyContent) -> Option<BoxPack> {
303 match justify {
304 JustifyContent::ContentDistribution(cd) => match cd {
305 ContentDistribution::SpaceBetween => Some(BoxPack::Justify),
306 _ => None,
307 },
308 JustifyContent::ContentPosition(None, pos) => match pos {
309 ContentPosition::Start | ContentPosition::FlexStart => Some(BoxPack::Start),
310 ContentPosition::End | ContentPosition::FlexEnd => Some(BoxPack::End),
311 ContentPosition::Center => Some(BoxPack::Center),
312 },
313 _ => None,
314 }
315 }
316}
317
318enum_property! {
319 pub enum BoxLines {
322 Single,
324 Multiple,
326 }
327}
328
329impl FromStandard<FlexWrap> for BoxLines {
330 fn from_standard(wrap: &FlexWrap) -> Option<BoxLines> {
331 match wrap {
332 FlexWrap::NoWrap => Some(BoxLines::Single),
333 FlexWrap::Wrap => Some(BoxLines::Multiple),
334 _ => None,
335 }
336 }
337}
338
339type BoxOrdinalGroup = CSSInteger;
340impl FromStandard<CSSInteger> for BoxOrdinalGroup {
341 fn from_standard(order: &CSSInteger) -> Option<BoxOrdinalGroup> {
342 Some(*order)
343 }
344}
345
346enum_property! {
349 pub enum FlexPack {
352 Start,
354 End,
356 Center,
358 Justify,
360 Distribute,
362 }
363}
364
365impl FromStandard<JustifyContent> for FlexPack {
366 fn from_standard(justify: &JustifyContent) -> Option<FlexPack> {
367 match justify {
368 JustifyContent::ContentDistribution(cd) => match cd {
369 ContentDistribution::SpaceBetween => Some(FlexPack::Justify),
370 ContentDistribution::SpaceAround => Some(FlexPack::Distribute),
371 _ => None,
372 },
373 JustifyContent::ContentPosition(None, pos) => match pos {
374 ContentPosition::Start | ContentPosition::FlexStart => Some(FlexPack::Start),
375 ContentPosition::End | ContentPosition::FlexEnd => Some(FlexPack::End),
376 ContentPosition::Center => Some(FlexPack::Center),
377 },
378 _ => None,
379 }
380 }
381}
382
383pub type FlexAlign = BoxAlign;
385
386enum_property! {
387 pub enum FlexItemAlign {
390 Auto,
392 Start,
394 End,
396 Center,
398 Baseline,
400 Stretch,
402 }
403}
404
405impl FromStandard<AlignSelf> for FlexItemAlign {
406 fn from_standard(justify: &AlignSelf) -> Option<FlexItemAlign> {
407 match justify {
408 AlignSelf::Auto => Some(FlexItemAlign::Auto),
409 AlignSelf::Stretch => Some(FlexItemAlign::Stretch),
410 AlignSelf::SelfPosition(None, pos) => match pos {
411 SelfPosition::Start | SelfPosition::FlexStart => Some(FlexItemAlign::Start),
412 SelfPosition::End | SelfPosition::FlexEnd => Some(FlexItemAlign::End),
413 SelfPosition::Center => Some(FlexItemAlign::Center),
414 _ => None,
415 },
416 _ => None,
417 }
418 }
419}
420
421enum_property! {
422 pub enum FlexLinePack {
425 Start,
427 End,
429 Center,
431 Justify,
433 Distribute,
435 Stretch,
437 }
438}
439
440impl FromStandard<AlignContent> for FlexLinePack {
441 fn from_standard(justify: &AlignContent) -> Option<FlexLinePack> {
442 match justify {
443 AlignContent::ContentDistribution(cd) => match cd {
444 ContentDistribution::SpaceBetween => Some(FlexLinePack::Justify),
445 ContentDistribution::SpaceAround => Some(FlexLinePack::Distribute),
446 ContentDistribution::Stretch => Some(FlexLinePack::Stretch),
447 _ => None,
448 },
449 AlignContent::ContentPosition(None, pos) => match pos {
450 ContentPosition::Start | ContentPosition::FlexStart => Some(FlexLinePack::Start),
451 ContentPosition::End | ContentPosition::FlexEnd => Some(FlexLinePack::End),
452 ContentPosition::Center => Some(FlexLinePack::Center),
453 },
454 _ => None,
455 }
456 }
457}
458
459#[derive(Default, Debug)]
460pub(crate) struct FlexHandler {
461 targets: Option<Browsers>,
462 direction: Option<(FlexDirection, VendorPrefix)>,
463 box_orient: Option<(BoxOrient, VendorPrefix)>,
464 box_direction: Option<(BoxDirection, VendorPrefix)>,
465 wrap: Option<(FlexWrap, VendorPrefix)>,
466 box_lines: Option<(BoxLines, VendorPrefix)>,
467 grow: Option<(CSSNumber, VendorPrefix)>,
468 box_flex: Option<(CSSNumber, VendorPrefix)>,
469 flex_positive: Option<(CSSNumber, VendorPrefix)>,
470 shrink: Option<(CSSNumber, VendorPrefix)>,
471 flex_negative: Option<(CSSNumber, VendorPrefix)>,
472 basis: Option<(LengthPercentageOrAuto, VendorPrefix)>,
473 preferred_size: Option<(LengthPercentageOrAuto, VendorPrefix)>,
474 order: Option<(CSSInteger, VendorPrefix)>,
475 box_ordinal_group: Option<(BoxOrdinalGroup, VendorPrefix)>,
476 flex_order: Option<(CSSInteger, VendorPrefix)>,
477 has_any: bool,
478}
479
480impl FlexHandler {
481 pub fn new(targets: Option<Browsers>) -> FlexHandler {
482 FlexHandler {
483 targets,
484 ..FlexHandler::default()
485 }
486 }
487}
488
489impl<'i> PropertyHandler<'i> for FlexHandler {
490 fn handle_property(
491 &mut self,
492 property: &Property<'i>,
493 dest: &mut DeclarationList<'i>,
494 _: &mut PropertyHandlerContext<'i, '_>,
495 ) -> bool {
496 use Property::*;
497
498 macro_rules! maybe_flush {
499 ($prop: ident, $val: expr, $vp: ident) => {{
500 if let Some((val, prefixes)) = &self.$prop {
503 if val != $val && !prefixes.contains(*$vp) {
504 self.flush(dest);
505 }
506 }
507 }};
508 }
509
510 macro_rules! property {
511 ($prop: ident, $val: expr, $vp: ident) => {{
512 maybe_flush!($prop, $val, $vp);
513
514 if let Some((val, prefixes)) = &mut self.$prop {
516 *val = $val.clone();
517 *prefixes |= *$vp;
518 } else {
519 self.$prop = Some(($val.clone(), *$vp));
520 self.has_any = true;
521 }
522 }};
523 }
524
525 match property {
526 FlexDirection(val, vp) => {
527 if self.targets.is_some() {
528 self.box_direction = None;
529 self.box_orient = None;
530 }
531 property!(direction, val, vp);
532 }
533 BoxOrient(val, vp) => property!(box_orient, val, vp),
534 BoxDirection(val, vp) => property!(box_direction, val, vp),
535 FlexWrap(val, vp) => {
536 if self.targets.is_some() {
537 self.box_lines = None;
538 }
539 property!(wrap, val, vp);
540 }
541 BoxLines(val, vp) => property!(box_lines, val, vp),
542 FlexFlow(val, vp) => {
543 if self.targets.is_some() {
544 self.box_direction = None;
545 self.box_orient = None;
546 }
547 property!(direction, &val.direction, vp);
548 property!(wrap, &val.wrap, vp);
549 }
550 FlexGrow(val, vp) => {
551 if self.targets.is_some() {
552 self.box_flex = None;
553 self.flex_positive = None;
554 }
555 property!(grow, val, vp);
556 }
557 BoxFlex(val, vp) => property!(box_flex, val, vp),
558 FlexPositive(val, vp) => property!(flex_positive, val, vp),
559 FlexShrink(val, vp) => {
560 if self.targets.is_some() {
561 self.flex_negative = None;
562 }
563 property!(shrink, val, vp);
564 }
565 FlexNegative(val, vp) => property!(flex_negative, val, vp),
566 FlexBasis(val, vp) => {
567 if self.targets.is_some() {
568 self.preferred_size = None;
569 }
570 property!(basis, val, vp);
571 }
572 FlexPreferredSize(val, vp) => property!(preferred_size, val, vp),
573 Flex(val, vp) => {
574 if self.targets.is_some() {
575 self.box_flex = None;
576 self.flex_positive = None;
577 self.flex_negative = None;
578 self.preferred_size = None;
579 }
580 maybe_flush!(grow, &val.grow, vp);
581 maybe_flush!(shrink, &val.shrink, vp);
582 maybe_flush!(basis, &val.basis, vp);
583 property!(grow, &val.grow, vp);
584 property!(shrink, &val.shrink, vp);
585 property!(basis, &val.basis, vp);
586 }
587 Order(val, vp) => {
588 if self.targets.is_some() {
589 self.box_ordinal_group = None;
590 self.flex_order = None;
591 }
592 property!(order, val, vp);
593 }
594 BoxOrdinalGroup(val, vp) => property!(box_ordinal_group, val, vp),
595 FlexOrder(val, vp) => property!(flex_order, val, vp),
596 Unparsed(val) if is_flex_property(&val.property_id) => {
597 self.flush(dest);
598 dest.push(property.clone()) }
600 _ => return false,
601 }
602
603 true
604 }
605
606 fn finalize(&mut self, dest: &mut DeclarationList, _: &mut PropertyHandlerContext<'i, '_>) {
607 self.flush(dest);
608 }
609}
610
611impl FlexHandler {
612 fn flush(&mut self, dest: &mut DeclarationList) {
613 if !self.has_any {
614 return;
615 }
616
617 self.has_any = false;
618
619 let mut direction = std::mem::take(&mut self.direction);
620 let mut wrap = std::mem::take(&mut self.wrap);
621 let mut grow = std::mem::take(&mut self.grow);
622 let mut shrink = std::mem::take(&mut self.shrink);
623 let mut basis = std::mem::take(&mut self.basis);
624 let box_orient = std::mem::take(&mut self.box_orient);
625 let box_direction = std::mem::take(&mut self.box_direction);
626 let box_flex = std::mem::take(&mut self.box_flex);
627 let box_ordinal_group = std::mem::take(&mut self.box_ordinal_group);
628 let box_lines = std::mem::take(&mut self.box_lines);
629 let flex_positive = std::mem::take(&mut self.flex_positive);
630 let flex_negative = std::mem::take(&mut self.flex_negative);
631 let preferred_size = std::mem::take(&mut self.preferred_size);
632 let order = std::mem::take(&mut self.order);
633 let flex_order = std::mem::take(&mut self.flex_order);
634
635 macro_rules! single_property {
636 ($prop: ident, $key: ident $(, 2012: $prop_2012: ident )? $(, 2009: $prop_2009: ident )?) => {
637 if let Some((val, prefix)) = $key {
638 if !prefix.is_empty() {
639 let mut prefix = prefix;
640 if prefix.contains(VendorPrefix::None) {
641 if let Some(targets) = self.targets {
642 prefix = Feature::$prop.prefixes_for(targets);
643
644 $(
646 let mut prefixes_2009 = VendorPrefix::empty();
647 if is_flex_2009(targets) {
648 prefixes_2009 |= VendorPrefix::WebKit;
649 }
650 if prefix.contains(VendorPrefix::Moz) {
651 prefixes_2009 |= VendorPrefix::Moz;
652 }
653 if !prefixes_2009.is_empty() {
654 if let Some(v) = $prop_2009::from_standard(&val) {
655 dest.push(Property::$prop_2009(v, prefixes_2009));
656 }
657 }
658 )?
659
660 $(
661 let mut ms = true;
662 if prefix.contains(VendorPrefix::Ms) {
663 dest.push(Property::$prop_2012(val.clone(), VendorPrefix::Ms));
664 ms = false;
665 }
666 if !ms {
667 prefix.remove(VendorPrefix::Ms);
668 }
669 )?
670
671 prefix.remove(VendorPrefix::Moz);
673 }
674 }
675 dest.push(Property::$prop(val, prefix))
676 }
677 }
678 };
679 }
680
681 macro_rules! legacy_property {
682 ($prop: ident, $key: expr) => {
683 if let Some((val, prefix)) = $key {
684 if !prefix.is_empty() {
685 dest.push(Property::$prop(val, prefix))
686 }
687 }
688 };
689 }
690
691 legacy_property!(BoxOrient, box_orient);
693 legacy_property!(BoxDirection, box_direction);
694 legacy_property!(BoxOrdinalGroup, box_ordinal_group);
695 legacy_property!(BoxFlex, box_flex);
696 legacy_property!(BoxLines, box_lines);
697 legacy_property!(FlexPositive, flex_positive);
698 legacy_property!(FlexNegative, flex_negative);
699 legacy_property!(FlexPreferredSize, preferred_size.clone());
700 legacy_property!(FlexOrder, flex_order.clone());
701
702 if let Some((direction, _)) = direction {
703 if let Some(targets) = self.targets {
704 let prefixes = Feature::FlexDirection.prefixes_for(targets);
705 let mut prefixes_2009 = VendorPrefix::empty();
706 if is_flex_2009(targets) {
707 prefixes_2009 |= VendorPrefix::WebKit;
708 }
709 if prefixes.contains(VendorPrefix::Moz) {
710 prefixes_2009 |= VendorPrefix::Moz;
711 }
712 if !prefixes_2009.is_empty() {
713 let (orient, dir) = direction.to_2009();
714 dest.push(Property::BoxOrient(orient, prefixes_2009));
715 dest.push(Property::BoxDirection(dir, prefixes_2009));
716 }
717 }
718 }
719
720 if let (Some((direction, dir_prefix)), Some((wrap, wrap_prefix))) = (&mut direction, &mut wrap) {
721 let intersection = *dir_prefix & *wrap_prefix;
722 if !intersection.is_empty() {
723 let mut prefix = intersection;
724 if prefix.contains(VendorPrefix::None) {
725 if let Some(targets) = self.targets {
726 prefix = Feature::FlexFlow.prefixes_for(targets);
727 prefix.remove(VendorPrefix::Moz);
729 }
730 }
731 dest.push(Property::FlexFlow(
732 FlexFlow {
733 direction: *direction,
734 wrap: *wrap,
735 },
736 prefix,
737 ));
738 dir_prefix.remove(intersection);
739 wrap_prefix.remove(intersection);
740 }
741 }
742
743 single_property!(FlexDirection, direction);
744 single_property!(FlexWrap, wrap, 2009: BoxLines);
745
746 if let Some(targets) = self.targets {
747 if let Some((grow, _)) = grow {
748 let prefixes = Feature::FlexGrow.prefixes_for(targets);
749 let mut prefixes_2009 = VendorPrefix::empty();
750 if is_flex_2009(targets) {
751 prefixes_2009 |= VendorPrefix::WebKit;
752 }
753 if prefixes.contains(VendorPrefix::Moz) {
754 prefixes_2009 |= VendorPrefix::Moz;
755 }
756 if !prefixes_2009.is_empty() {
757 dest.push(Property::BoxFlex(grow, prefixes_2009));
758 }
759 }
760 }
761
762 if let (Some((grow, grow_prefix)), Some((shrink, shrink_prefix)), Some((basis, basis_prefix))) =
763 (&mut grow, &mut shrink, &mut basis)
764 {
765 let intersection = *grow_prefix & *shrink_prefix & *basis_prefix;
766 if !intersection.is_empty() {
767 let mut prefix = intersection;
768 if prefix.contains(VendorPrefix::None) {
769 if let Some(targets) = self.targets {
770 prefix = Feature::Flex.prefixes_for(targets);
771 prefix.remove(VendorPrefix::Moz);
773 }
774 }
775 dest.push(Property::Flex(
776 Flex {
777 grow: *grow,
778 shrink: *shrink,
779 basis: basis.clone(),
780 },
781 prefix,
782 ));
783 grow_prefix.remove(intersection);
784 shrink_prefix.remove(intersection);
785 basis_prefix.remove(intersection);
786 }
787 }
788
789 single_property!(FlexGrow, grow, 2012: FlexPositive);
790 single_property!(FlexShrink, shrink, 2012: FlexNegative);
791 single_property!(FlexBasis, basis, 2012: FlexPreferredSize);
792 single_property!(Order, order, 2012: FlexOrder, 2009: BoxOrdinalGroup);
793 }
794}
795
796#[inline]
797fn is_flex_property(property_id: &PropertyId) -> bool {
798 match property_id {
799 PropertyId::FlexDirection(_)
800 | PropertyId::BoxOrient(_)
801 | PropertyId::BoxDirection(_)
802 | PropertyId::FlexWrap(_)
803 | PropertyId::BoxLines(_)
804 | PropertyId::FlexFlow(_)
805 | PropertyId::FlexGrow(_)
806 | PropertyId::BoxFlex(_)
807 | PropertyId::FlexPositive(_)
808 | PropertyId::FlexShrink(_)
809 | PropertyId::FlexNegative(_)
810 | PropertyId::FlexBasis(_)
811 | PropertyId::FlexPreferredSize(_)
812 | PropertyId::Flex(_)
813 | PropertyId::Order(_)
814 | PropertyId::BoxOrdinalGroup(_)
815 | PropertyId::FlexOrder(_) => true,
816 _ => false,
817 }
818}