#![warn(unused_must_use)]
use crate as css;
use bun_alloc::ArenaVecExt as _;
use crate::properties::{Property, PropertyId};
use css::css_properties::align::{AlignContent, AlignItems, AlignSelf, JustifyContent};
use css::css_values::length::{LengthPercentage, LengthPercentageOrAuto};
use css::css_values::number::{CSSInteger, CSSNumber, CSSNumberFns};
use css::prefixes::Feature as PrefixFeature;
use css::{PrintErr, Printer, VendorPrefix};
use css::prefixes::is_flex_2009;
#[derive(Clone, Copy, Default, PartialEq, Eq, Hash, css::DefineEnumProperty)]
pub enum FlexDirection {
#[default]
Row,
RowReverse,
Column,
ColumnReverse,
}
impl FlexDirection {
pub(crate) fn to_2009(self) -> (BoxOrient, BoxDirection) {
match self {
FlexDirection::Row => (BoxOrient::Horizontal, BoxDirection::Normal),
FlexDirection::Column => (BoxOrient::Vertical, BoxDirection::Normal),
FlexDirection::RowReverse => (BoxOrient::Horizontal, BoxDirection::Reverse),
FlexDirection::ColumnReverse => (BoxOrient::Vertical, BoxDirection::Reverse),
}
}
}
#[derive(Clone, Copy, Default, PartialEq, Eq, Hash, css::DefineEnumProperty)]
pub enum FlexWrap {
#[default]
Nowrap,
Wrap,
WrapReverse,
}
#[derive(Clone, PartialEq, Eq)]
pub struct FlexFlow {
pub direction: FlexDirection,
pub wrap: FlexWrap,
}
impl FlexFlow {
pub(crate) fn parse(input: &mut css::Parser) -> css::Result<Self> {
let mut direction: Option<FlexDirection> = None;
let mut wrap: Option<FlexWrap> = None;
loop {
if direction.is_none() {
if let Ok(value) = input.try_parse(FlexDirection::parse) {
direction = Some(value);
continue;
}
}
if wrap.is_none() {
if let Ok(value) = input.try_parse(FlexWrap::parse) {
wrap = Some(value);
continue;
}
}
break;
}
Ok(FlexFlow {
direction: direction.unwrap_or(FlexDirection::Row),
wrap: wrap.unwrap_or(FlexWrap::Nowrap),
})
}
pub(crate) fn to_css(&self, dest: &mut Printer) -> Result<(), PrintErr> {
let mut needs_space = false;
if self.direction != FlexDirection::default() || self.wrap == FlexWrap::default() {
self.direction.to_css(dest)?;
needs_space = true;
}
if self.wrap != FlexWrap::default() {
if needs_space {
dest.write_str(" ")?;
}
self.wrap.to_css(dest)?;
}
Ok(())
}
}
#[derive(Clone, PartialEq)]
pub struct Flex {
pub grow: CSSNumber,
pub shrink: CSSNumber,
pub basis: LengthPercentageOrAuto,
}
impl Flex {
pub(crate) fn parse(input: &mut css::Parser) -> css::Result<Self> {
if input
.try_parse(|i| i.expect_ident_matching(b"none"))
.is_ok()
{
return Ok(Flex {
grow: 0.0,
shrink: 0.0,
basis: LengthPercentageOrAuto::Auto,
});
}
let mut grow: Option<CSSNumber> = None;
let mut shrink: Option<CSSNumber> = None;
let mut basis: Option<LengthPercentageOrAuto> = None;
loop {
if grow.is_none() {
if let Ok(value) = input.try_parse(CSSNumberFns::parse) {
grow = Some(value);
shrink = input.try_parse(CSSNumberFns::parse).ok();
continue;
}
}
if basis.is_none() {
if let Ok(value) = input.try_parse(LengthPercentageOrAuto::parse) {
basis = Some(value);
continue;
}
}
break;
}
Ok(Flex {
grow: grow.unwrap_or(1.0),
shrink: shrink.unwrap_or(1.0),
basis: basis.unwrap_or(LengthPercentageOrAuto::Length(
LengthPercentage::Percentage(css::css_values::percentage::Percentage { v: 0.0 }),
)),
})
}
pub(crate) fn to_css(&self, dest: &mut Printer) -> Result<(), PrintErr> {
if self.grow == 0.0
&& self.shrink == 0.0
&& matches!(self.basis, LengthPercentageOrAuto::Auto)
{
dest.write_str("none")?;
return Ok(());
}
#[derive(PartialEq, Eq)]
enum ZeroKind {
NonZero,
Length,
Percentage,
}
let basis_kind = match &self.basis {
LengthPercentageOrAuto::Length(lp) => 'brk: {
if let LengthPercentage::Dimension(d) = lp {
if d.is_zero() {
break 'brk ZeroKind::Length;
}
}
if let LengthPercentage::Percentage(p) = lp {
if p.is_zero() {
break 'brk ZeroKind::Percentage;
}
}
ZeroKind::NonZero
}
_ => ZeroKind::NonZero,
};
if self.grow != 1.0 || self.shrink != 1.0 || basis_kind != ZeroKind::NonZero {
CSSNumberFns::to_css(self.grow, dest)?;
if self.shrink != 1.0 || basis_kind == ZeroKind::Length {
dest.write_str(" ")?;
CSSNumberFns::to_css(self.shrink, dest)?;
}
}
if basis_kind != ZeroKind::Percentage {
if self.grow != 1.0 || self.shrink != 1.0 || basis_kind == ZeroKind::Length {
dest.write_str(" ")?;
}
self.basis.to_css(dest)?;
}
Ok(())
}
}
#[derive(Clone, Copy, PartialEq, Eq, Hash, css::DefineEnumProperty)]
pub enum BoxOrient {
Horizontal,
Vertical,
InlineAxis,
BlockAxis,
}
#[derive(Clone, Copy, PartialEq, Eq, Hash, css::DefineEnumProperty)]
pub enum BoxDirection {
Normal,
Reverse,
}
pub(crate) type FlexAlign = BoxAlign;
#[derive(Clone, Copy, PartialEq, Eq, Hash, css::DefineEnumProperty)]
pub enum BoxAlign {
Start,
End,
Center,
Baseline,
Stretch,
}
impl BoxAlign {
pub(crate) fn from_standard(align: &AlignItems) -> Option<BoxAlign> {
use css::css_properties::align::SelfPosition;
match align {
AlignItems::SelfPosition(sp) => {
if sp.overflow.is_none() {
match sp.value {
SelfPosition::Start | SelfPosition::FlexStart => Some(BoxAlign::Start),
SelfPosition::End | SelfPosition::FlexEnd => Some(BoxAlign::End),
SelfPosition::Center => Some(BoxAlign::Center),
_ => None,
}
} else {
None
}
}
AlignItems::Stretch => Some(BoxAlign::Stretch),
_ => None,
}
}
}
#[derive(Clone, Copy, PartialEq, Eq, Hash, css::DefineEnumProperty)]
pub enum BoxPack {
Start,
End,
Center,
Justify,
}
impl BoxPack {
pub(crate) fn from_standard(justify: &JustifyContent) -> Option<BoxPack> {
use css::css_properties::align::{ContentDistribution, ContentPosition};
match justify {
JustifyContent::ContentDistribution(cd) => match cd {
ContentDistribution::SpaceBetween => Some(BoxPack::Justify),
_ => None,
},
JustifyContent::ContentPosition(cp) => {
if cp.overflow.is_none() {
match cp.value {
ContentPosition::Start | ContentPosition::FlexStart => Some(BoxPack::Start),
ContentPosition::End | ContentPosition::FlexEnd => Some(BoxPack::End),
ContentPosition::Center => Some(BoxPack::Center),
}
} else {
None
}
}
_ => None,
}
}
}
#[derive(Clone, Copy, PartialEq, Eq, Hash, css::DefineEnumProperty)]
pub enum BoxLines {
Single,
Multiple,
}
impl BoxLines {
pub(crate) fn from_standard(wrap: FlexWrap) -> Option<BoxLines> {
match wrap {
FlexWrap::Nowrap => Some(BoxLines::Single),
FlexWrap::Wrap => Some(BoxLines::Multiple),
_ => None,
}
}
}
#[derive(Clone, Copy, PartialEq, Eq, Hash, css::DefineEnumProperty)]
pub enum FlexPack {
Start,
End,
Center,
Justify,
Distribute,
}
impl FlexPack {
pub(crate) fn from_standard(justify: &JustifyContent) -> Option<FlexPack> {
use css::css_properties::align::{ContentDistribution, ContentPosition};
match justify {
JustifyContent::ContentDistribution(cd) => match cd {
ContentDistribution::SpaceBetween => Some(FlexPack::Justify),
ContentDistribution::SpaceAround => Some(FlexPack::Distribute),
_ => None,
},
JustifyContent::ContentPosition(cp) => {
if cp.overflow.is_none() {
match cp.value {
ContentPosition::Start | ContentPosition::FlexStart => {
Some(FlexPack::Start)
}
ContentPosition::End | ContentPosition::FlexEnd => Some(FlexPack::End),
ContentPosition::Center => Some(FlexPack::Center),
}
} else {
None
}
}
_ => None,
}
}
}
#[derive(Clone, Copy, PartialEq, Eq, Hash, css::DefineEnumProperty)]
pub enum FlexItemAlign {
Auto,
Start,
End,
Center,
Baseline,
Stretch,
}
impl FlexItemAlign {
pub(crate) fn from_standard(justify: &AlignSelf) -> Option<FlexItemAlign> {
use css::css_properties::align::SelfPosition;
match justify {
AlignSelf::Auto => Some(FlexItemAlign::Auto),
AlignSelf::Stretch => Some(FlexItemAlign::Stretch),
AlignSelf::SelfPosition(sp) => {
if sp.overflow.is_none() {
match sp.value {
SelfPosition::Start | SelfPosition::FlexStart => Some(FlexItemAlign::Start),
SelfPosition::End | SelfPosition::FlexEnd => Some(FlexItemAlign::End),
SelfPosition::Center => Some(FlexItemAlign::Center),
_ => None,
}
} else {
None
}
}
_ => None,
}
}
}
#[derive(Clone, Copy, PartialEq, Eq, Hash, css::DefineEnumProperty)]
pub enum FlexLinePack {
Start,
End,
Center,
Justify,
Distribute,
Stretch,
}
impl FlexLinePack {
pub(crate) fn from_standard(justify: &AlignContent) -> Option<FlexLinePack> {
use css::css_properties::align::{ContentDistribution, ContentPosition};
match justify {
AlignContent::ContentDistribution(cd) => match cd {
ContentDistribution::SpaceBetween => Some(FlexLinePack::Justify),
ContentDistribution::SpaceAround => Some(FlexLinePack::Distribute),
ContentDistribution::Stretch => Some(FlexLinePack::Stretch),
_ => None,
},
AlignContent::ContentPosition(cp) => {
if cp.overflow.is_none() {
match cp.value {
ContentPosition::Start | ContentPosition::FlexStart => {
Some(FlexLinePack::Start)
}
ContentPosition::End | ContentPosition::FlexEnd => Some(FlexLinePack::End),
ContentPosition::Center => Some(FlexLinePack::Center),
}
} else {
None
}
}
_ => None,
}
}
}
pub(crate) type BoxOrdinalGroup = CSSInteger;
#[derive(Default)]
pub struct FlexHandler {
pub direction: Option<(FlexDirection, VendorPrefix)>,
pub box_orient: Option<(BoxOrient, VendorPrefix)>,
pub box_direction: Option<(BoxDirection, VendorPrefix)>,
pub wrap: Option<(FlexWrap, VendorPrefix)>,
pub box_lines: Option<(BoxLines, VendorPrefix)>,
pub grow: Option<(CSSNumber, VendorPrefix)>,
pub box_flex: Option<(CSSNumber, VendorPrefix)>,
pub flex_positive: Option<(CSSNumber, VendorPrefix)>,
pub shrink: Option<(CSSNumber, VendorPrefix)>,
pub flex_negative: Option<(CSSNumber, VendorPrefix)>,
pub basis: Option<(LengthPercentageOrAuto, VendorPrefix)>,
pub preferred_size: Option<(LengthPercentageOrAuto, VendorPrefix)>,
pub order: Option<(CSSInteger, VendorPrefix)>,
pub box_ordinal_group: Option<(BoxOrdinalGroup, VendorPrefix)>,
pub flex_order: Option<(CSSInteger, VendorPrefix)>,
pub has_any: bool,
}
impl FlexHandler {
pub(crate) fn handle_property(
&mut self,
property: &Property,
dest: &mut css::DeclarationList,
context: &mut css::PropertyHandlerContext,
) -> bool {
macro_rules! maybe_flush {
($prop:ident, $val:expr, $vp:expr) => {{
if let Some(field) = &self.$prop {
if !(field.0 == *$val) && !field.1.contains(*$vp) {
self.flush(dest, context);
}
}
}};
}
macro_rules! property_helper {
($prop:ident, $val:expr, $vp:expr) => {{
maybe_flush!($prop, $val, $vp);
if let Some(field) = &mut self.$prop {
field.0 = ($val).clone();
field.1.insert(*$vp);
} else {
self.$prop = Some((($val).clone(), *$vp));
self.has_any = true;
}
}};
}
match property {
Property::FlexDirection(val) => {
if context.targets.browsers.is_some() {
self.box_direction = None;
self.box_orient = None;
}
property_helper!(direction, &val.0, &val.1);
}
Property::BoxOrient(val) => property_helper!(box_orient, &val.0, &val.1),
Property::BoxDirection(val) => property_helper!(box_direction, &val.0, &val.1),
Property::FlexWrap(val) => {
if context.targets.browsers.is_some() {
self.box_lines = None;
}
property_helper!(wrap, &val.0, &val.1);
}
Property::BoxLines(val) => property_helper!(box_lines, &val.0, &val.1),
Property::FlexFlow(val) => {
if context.targets.browsers.is_some() {
self.box_direction = None;
self.box_orient = None;
}
property_helper!(direction, &val.0.direction, &val.1);
property_helper!(wrap, &val.0.wrap, &val.1);
}
Property::FlexGrow(val) => {
if context.targets.browsers.is_some() {
self.box_flex = None;
self.flex_positive = None;
}
property_helper!(grow, &val.0, &val.1);
}
Property::BoxFlex(val) => property_helper!(box_flex, &val.0, &val.1),
Property::FlexPositive(val) => property_helper!(flex_positive, &val.0, &val.1),
Property::FlexShrink(val) => {
if context.targets.browsers.is_some() {
self.flex_negative = None;
}
property_helper!(shrink, &val.0, &val.1);
}
Property::FlexNegative(val) => property_helper!(flex_negative, &val.0, &val.1),
Property::FlexBasis(val) => {
if context.targets.browsers.is_some() {
self.preferred_size = None;
}
property_helper!(basis, &val.0, &val.1);
}
Property::FlexPreferredSize(val) => property_helper!(preferred_size, &val.0, &val.1),
Property::Flex(val) => {
if context.targets.browsers.is_some() {
self.box_flex = None;
self.flex_positive = None;
self.flex_negative = None;
self.preferred_size = None;
}
maybe_flush!(grow, &val.0.grow, &val.1);
maybe_flush!(shrink, &val.0.shrink, &val.1);
maybe_flush!(basis, &val.0.basis, &val.1);
property_helper!(grow, &val.0.grow, &val.1);
property_helper!(shrink, &val.0.shrink, &val.1);
property_helper!(basis, &val.0.basis, &val.1);
}
Property::Order(val) => {
if context.targets.browsers.is_some() {
self.box_ordinal_group = None;
self.flex_order = None;
}
property_helper!(order, &val.0, &val.1);
}
Property::BoxOrdinalGroup(val) => property_helper!(box_ordinal_group, &val.0, &val.1),
Property::FlexOrder(val) => property_helper!(flex_order, &val.0, &val.1),
Property::Unparsed(val) => {
if Self::is_flex_property(&val.property_id) {
self.flush(dest, context);
let bump = dest.bump();
dest.push(Property::Unparsed(val.deep_clone(bump)));
} else {
return false;
}
}
_ => return false,
}
true
}
pub(crate) fn finalize(
&mut self,
dest: &mut css::DeclarationList,
context: &mut css::PropertyHandlerContext,
) {
self.flush(dest, context);
}
fn flush(
&mut self,
dest: &mut css::DeclarationList,
context: &mut css::PropertyHandlerContext,
) {
if !self.has_any {
return;
}
self.has_any = false;
let mut direction: Option<(FlexDirection, VendorPrefix)> = self.direction.take();
let mut wrap: Option<(FlexWrap, VendorPrefix)> = self.wrap.take();
let mut grow: Option<(CSSNumber, VendorPrefix)> = self.grow.take();
let mut shrink: Option<(CSSNumber, VendorPrefix)> = self.shrink.take();
let mut basis = self.basis.take();
let mut box_orient = self.box_orient.take();
let mut box_direction = self.box_direction.take();
let mut box_flex = self.box_flex.take();
let mut box_ordinal_group = self.box_ordinal_group.take();
let mut box_lines = self.box_lines.take();
let mut flex_positive = self.flex_positive.take();
let mut flex_negative = self.flex_negative.take();
let mut preferred_size = self.preferred_size.take();
let mut order = self.order.take();
let mut flex_order = self.flex_order.take();
macro_rules! legacy_property {
($variant:ident, $key:expr) => {{
if let Some(value) = $key {
let val = value.0;
let prefix = value.1;
if !prefix.is_empty() {
dest.push(Property::$variant((val, prefix)));
} else {
}
}
}};
}
legacy_property!(BoxOrient, box_orient.take());
legacy_property!(BoxDirection, box_direction.take());
legacy_property!(BoxOrdinalGroup, box_ordinal_group.take());
legacy_property!(BoxFlex, box_flex.take());
legacy_property!(BoxLines, box_lines.take());
legacy_property!(FlexPositive, flex_positive.take());
legacy_property!(FlexNegative, flex_negative.take());
legacy_property!(FlexPreferredSize, preferred_size.take());
legacy_property!(FlexOrder, flex_order.take());
if let Some(val) = &direction {
let dir = val.0;
if let Some(targets) = &context.targets.browsers {
let prefixes = context
.targets
.prefixes(VendorPrefix::NONE, PrefixFeature::FlexDirection);
let mut prefixes_2009 = VendorPrefix::empty();
if is_flex_2009(targets) {
prefixes_2009.insert(VendorPrefix::WEBKIT);
}
if prefixes.contains(VendorPrefix::MOZ) {
prefixes_2009.insert(VendorPrefix::MOZ);
}
if !prefixes_2009.is_empty() {
let (orient, newdir) = dir.to_2009();
dest.push(Property::BoxOrient((orient, prefixes_2009)));
dest.push(Property::BoxDirection((newdir, prefixes_2009)));
}
}
}
if let (Some(dir_val), Some(wrap_val)) = (&mut direction, &mut wrap) {
let dir: &FlexDirection = &dir_val.0;
let dir_prefix: &mut VendorPrefix = &mut dir_val.1;
let wrapinner: &FlexWrap = &wrap_val.0;
let wrap_prefix: &mut VendorPrefix = &mut wrap_val.1;
let intersection = dir_prefix.intersection(*wrap_prefix);
if !intersection.is_empty() {
let mut prefix = context
.targets
.prefixes(intersection, PrefixFeature::FlexFlow);
prefix.remove(VendorPrefix::MOZ);
dest.push(Property::FlexFlow((
FlexFlow {
direction: *dir,
wrap: *wrapinner,
},
prefix,
)));
dir_prefix.remove(intersection);
wrap_prefix.remove(intersection);
}
}
macro_rules! single_property {
($variant:ident, $key:expr, prop_2012 = None, prop_2009 = None, feature = $feature:ident) => {{
single_property!(@inner $variant, $key, $feature, |_val, _prefix, _prefixes_2009| {}, |_val, _prefix: &mut VendorPrefix| {});
}};
($variant:ident, $key:expr, prop_2012 = $p2012:ident, prop_2009 = None, feature = $feature:ident) => {{
single_property!(@inner $variant, $key, $feature, |_val, _prefix, _prefixes_2009| {}, |val, prefix: &mut VendorPrefix| {
let mut ms = true;
if prefix.contains(VendorPrefix::MS) {
dest.push(Property::$p2012((val, VendorPrefix::MS)));
ms = false;
}
if !ms {
prefix.remove(VendorPrefix::MS);
}
});
}};
($variant:ident, $key:expr, prop_2012 = None, prop_2009 = ($ty2009:ty, $v2009:ident), feature = $feature:ident) => {{
single_property!(@inner $variant, $key, $feature, |val, _prefix, prefixes_2009: VendorPrefix| {
let s = <$ty2009>::from_standard(val);
if let Some(v) = s {
dest.push(Property::$v2009((v, prefixes_2009)));
}
}, |_val, _prefix: &mut VendorPrefix| {});
}};
($variant:ident, $key:expr, prop_2012 = $p2012:ident, prop_2009 = (BoxOrdinalGroup, $v2009:ident), feature = $feature:ident) => {{
single_property!(@inner $variant, $key, $feature, |val, _prefix, prefixes_2009: VendorPrefix| {
let s: Option<i32> = Some(val);
if let Some(v) = s {
dest.push(Property::$v2009((v, prefixes_2009)));
}
}, |val, prefix: &mut VendorPrefix| {
let mut ms = true;
if prefix.contains(VendorPrefix::MS) {
dest.push(Property::$p2012((val, VendorPrefix::MS)));
ms = false;
}
if !ms {
prefix.remove(VendorPrefix::MS);
}
});
}};
(@inner $variant:ident, $key:expr, $feature:ident, $body_2009:expr, $body_2012:expr) => {{
if let Some(value) = $key {
let val = value.0;
let mut prefix = value.1;
if !prefix.is_empty() {
prefix = context.targets.prefixes(prefix, PrefixFeature::$feature);
#[allow(unused)]
{
if prefix.contains(VendorPrefix::NONE) {
if let Some(targets) = &context.targets.browsers {
let mut prefixes_2009 = VendorPrefix::empty();
if is_flex_2009(targets) {
prefixes_2009.insert(VendorPrefix::WEBKIT);
}
if prefix.contains(VendorPrefix::MOZ) {
prefixes_2009.insert(VendorPrefix::MOZ);
}
if !prefixes_2009.is_empty() {
($body_2009)(val.clone(), &prefix, prefixes_2009);
}
}
}
}
($body_2012)(val.clone(), &mut prefix);
prefix.remove(VendorPrefix::MOZ);
dest.push(Property::$variant((val, prefix)));
}
}
}};
}
single_property!(
FlexDirection,
direction.take(),
prop_2012 = None,
prop_2009 = None,
feature = FlexDirection
);
single_property!(
FlexWrap,
wrap.take(),
prop_2012 = None,
prop_2009 = (BoxLines, BoxLines),
feature = FlexWrap
);
if let Some(targets) = &context.targets.browsers {
if let Some(val) = &grow {
let g = val.0;
let prefixes = context
.targets
.prefixes(VendorPrefix::NONE, PrefixFeature::FlexGrow);
let mut prefixes_2009 = VendorPrefix::empty();
if is_flex_2009(targets) {
prefixes_2009.insert(VendorPrefix::WEBKIT);
}
if prefixes.contains(VendorPrefix::MOZ) {
prefixes_2009.insert(VendorPrefix::MOZ);
}
if !prefixes_2009.is_empty() {
dest.push(Property::BoxFlex((g, prefixes_2009)));
}
}
}
if let (Some(g_val), Some(s_val), Some(b_val)) = (&mut grow, &mut shrink, &mut basis) {
let g = g_val.0;
let g_prefix: &mut VendorPrefix = &mut g_val.1;
let s = s_val.0;
let s_prefix: &mut VendorPrefix = &mut s_val.1;
let b = b_val.0.clone();
let b_prefix: &mut VendorPrefix = &mut b_val.1;
let intersection = g_prefix.intersection(s_prefix.intersection(*b_prefix));
if !intersection.is_empty() {
let mut prefix = context.targets.prefixes(intersection, PrefixFeature::Flex);
prefix.remove(VendorPrefix::MOZ);
dest.push(Property::Flex((
Flex {
grow: g,
shrink: s,
basis: b,
},
prefix,
)));
g_prefix.remove(intersection);
s_prefix.remove(intersection);
b_prefix.remove(intersection);
}
}
single_property!(
FlexGrow,
grow.take(),
prop_2012 = FlexPositive,
prop_2009 = None,
feature = FlexGrow
);
single_property!(
FlexShrink,
shrink.take(),
prop_2012 = FlexNegative,
prop_2009 = None,
feature = FlexShrink
);
single_property!(
FlexBasis,
basis.take(),
prop_2012 = FlexPreferredSize,
prop_2009 = None,
feature = FlexBasis
);
single_property!(
Order,
order.take(),
prop_2012 = FlexOrder,
prop_2009 = (BoxOrdinalGroup, BoxOrdinalGroup),
feature = Order
);
}
fn is_flex_property(property_id: &PropertyId) -> bool {
matches!(
property_id,
PropertyId::FlexDirection(..)
| PropertyId::BoxOrient(..)
| PropertyId::BoxDirection(..)
| PropertyId::FlexWrap(..)
| PropertyId::BoxLines(..)
| PropertyId::FlexFlow(..)
| PropertyId::FlexGrow(..)
| PropertyId::BoxFlex(..)
| PropertyId::FlexPositive(..)
| PropertyId::FlexShrink(..)
| PropertyId::FlexNegative(..)
| PropertyId::FlexBasis(..)
| PropertyId::FlexPreferredSize(..)
| PropertyId::Flex(..)
| PropertyId::Order(..)
| PropertyId::BoxOrdinalGroup(..)
| PropertyId::FlexOrder(..)
)
}
}