Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[WIP]: Enable Flex declarations #69

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 19 additions & 17 deletions colosseum/declaration.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
from . import engine as css_engine
from . import parser
from . import engine as css_engine, parser
from .constants import ( # noqa
ALIGN_CONTENT_CHOICES, ALIGN_ITEMS_CHOICES, ALIGN_SELF_CHOICES, AUTO,
BACKGROUND_COLOR_CHOICES, BORDER_COLLAPSE_CHOICES, BORDER_COLOR_CHOICES,
Expand All @@ -15,16 +14,19 @@
NOWRAP, ORDER_CHOICES, ORPHANS_CHOICES, OUTLINE_COLOR_CHOICES,
OUTLINE_STYLE_CHOICES, OUTLINE_WIDTH_CHOICES, OVERFLOW_CHOICES,
PADDING_CHOICES, PAGE_BREAK_AFTER_CHOICES, PAGE_BREAK_BEFORE_CHOICES,
PAGE_BREAK_INSIDE_CHOICES, POSITION_CHOICES, QUOTES_CHOICES, ROW,
SEPARATE, SHOW, SIZE_CHOICES, STATIC, STRETCH, TABLE_LAYOUT_CHOICES,
PAGE_BREAK_INSIDE_CHOICES, POSITION_CHOICES, QUOTES_CHOICES, ROW, SEPARATE,
SHOW, SIZE_CHOICES, STATIC, STRETCH, TABLE_LAYOUT_CHOICES,
TEXT_ALIGN_CHOICES, TEXT_DECORATION_CHOICES, TEXT_INDENT_CHOICES,
TEXT_TRANSFORM_CHOICES, TOP, TRANSPARENT, UNICODE_BIDI_CHOICES,
VISIBILITY_CHOICES, VISIBLE, WHITE_SPACE_CHOICES, WIDOWS_CHOICES,
WORD_SPACING_CHOICES, Z_INDEX_CHOICES, OtherProperty,
TextAlignInitialValue, default, CURSOR_CHOICES,
)
from .exceptions import ValidationError
from .wrappers import Border, BorderBottom, BorderLeft, BorderRight, BorderTop, Outline
from .wrappers import ( # noqa
Border, BorderBottom, BorderLeft, BorderRight, BorderTop, Flex, FlexFlow,
Outline
)

_CSS_PROPERTIES = set()

Expand Down Expand Up @@ -424,36 +426,36 @@ def __init__(self, **style):

# 5. Ordering and orientation ########################################
# 5.1 Flex flow direction
# flex_direction = validated_property('flex_direction', choices=FLEX_DIRECTION_CHOICES, initial=ROW)
flex_direction = validated_property('flex_direction', choices=FLEX_DIRECTION_CHOICES, initial=ROW)

# 5.2 Flex line wrapping
# flex_wrap = validated_property('flex_wrap', choices=FLEX_WRAP_CHOICES, initial=NOWRAP)
flex_wrap = validated_property('flex_wrap', choices=FLEX_WRAP_CHOICES, initial=NOWRAP)

# 5.3 Flex direction and wrap
# flex_flow =
flex_flow = validated_shorthand_property('flex_flow', parser=parser.flex_flow, wrapper=FlexFlow)

# 5.4 Display order
# order = validated_property('order', choices=ORDER_CHOICES, initial=0)
order = validated_property('order', choices=ORDER_CHOICES, initial=0)

# 7. Flexibility #####################################################
# 7.2 Components of flexibility
# flex_grow = validated_property('flex_grow', choices=FLEX_GROW_CHOICES, initial=0)
# flex_shrink = validated_property('flex_shrink', choices=FLEX_SHRINK_CHOICES, initial=1)
# flex_basis = validated_property('flex_basis', choices=FLEX_BASIS_CHOICES, initial=AUTO)
flex_grow = validated_property('flex_grow', choices=FLEX_GROW_CHOICES, initial=0)
flex_shrink = validated_property('flex_shrink', choices=FLEX_SHRINK_CHOICES, initial=1)
flex_basis = validated_property('flex_basis', choices=FLEX_BASIS_CHOICES, initial=AUTO)

# 7.1 The 'flex' shorthand
# flex =
flex = validated_shorthand_property('flex', parser=parser.flex, wrapper=Flex)

# 8. Alignment #######################################################
# 8.2 Axis alignment
# justify_content = validated_property('justify_content', choices=JUSTIFY_CONTENT_CHOICES, initial=FLEX_START)
justify_content = validated_property('justify_content', choices=JUSTIFY_CONTENT_CHOICES, initial=FLEX_START)

# 8.3 Cros-axis alignment
# align_items = validated_property('align_items', choices=ALIGN_ITEMS_CHOICES, initial=STRETCH)
# align_self = validated_property('align_self', choices=ALIGN_SELF_CHOICES, initial=AUTO)
align_items = validated_property('align_items', choices=ALIGN_ITEMS_CHOICES, initial=STRETCH)
align_self = validated_property('align_self', choices=ALIGN_SELF_CHOICES, initial=AUTO)

# 8.4 Packing flex lines
# align_content = validated_property('align_content', choices=ALIGN_CONTENT_CHOICES, initial=STRETCH)
align_content = validated_property('align_content', choices=ALIGN_CONTENT_CHOICES, initial=STRETCH)

######################################################################
# Grid properties
Expand Down
125 changes: 125 additions & 0 deletions colosseum/parser.py
Original file line number Diff line number Diff line change
Expand Up @@ -445,3 +445,128 @@ def cursor(values):
raise ValueError('Value {value} is not a valid cursor value'.format(value=value))

return Cursor(validated_values)


##############################################################################
# Flex Flow
##############################################################################
def _parse_flex_flow_property_part(value, flex_flow_dict):
"""Parse flex_flow shorthand property part for known properties."""
from .constants import FLEX_DIRECTION_CHOICES, FLEX_WRAP_CHOICES

property_validators = {
'flex_direction': FLEX_DIRECTION_CHOICES,
'flex_wrap': FLEX_WRAP_CHOICES,
}

for property_name, choices in property_validators.items():
try:
value = choices.validate(value)
except (ValueError, ValidationError):
continue

if property_name in flex_flow_dict:
raise ValueError('Invalid duplicated property!')

flex_flow_dict[property_name] = value
return flex_flow_dict

raise ValueError('Flex flow value "{value}" not valid!'.format(value=value))


def flex_flow(value):
"""
Parse flex flow string into a dictionary of properties.

The font CSS property is a shorthand for flex-wrap and flex-direction.

Reference:
- https://www.w3.org/TR/css-flexbox-1/#flex-flow-property
"""
if value:
if isinstance(value, str):
values = [val.strip() for val in value.split()]
elif isinstance(value, Sequence):
values = value
else:
raise ValueError('Unknown flex flow %s ' % value)
else:
raise ValueError('Unknown flex flow %s ' % value)

# We iteratively split by the first left hand space found and try to validate if that part
# is a valid <flex-wrap> or <flex-direction> (which can come in any order)

# We use this dictionary to store parsed values and check that values properties are not
# duplicated
flex_flow_dict = {}
for idx, part in enumerate(values):
if idx > 1:
# Flex flow can have a maximum of 2 parts
raise ValueError('Flex flow property shorthand contains too many parts!')

flex_flow_dict = _parse_flex_flow_property_part(part, flex_flow_dict)

return flex_flow_dict


##############################################################################
# Flex
##############################################################################
def _parse_flex_property_part(value, flex_dict):
"""Parse flex shorthand property part for known properties."""
from .constants import FLEX_GROW_CHOICES, FLEX_SHRINK_CHOICES, FLEX_BASIS_CHOICES

property_validators = {
'flex_grow': FLEX_GROW_CHOICES,
'flex_shrink': FLEX_SHRINK_CHOICES,
'flex_basis': FLEX_BASIS_CHOICES,
}

for property_name, choices in property_validators.items():
try:
value = choices.validate(value)
except (ValueError, ValidationError):
continue

if property_name in flex_dict:
raise ValueError('Invalid duplicated property!')

flex_dict[property_name] = value
return flex_dict

raise ValueError('Flex value "{value}" not valid!'.format(value=value))


def flex(value):
"""
Parse flex string into a dictionary of properties.

The font CSS property is a shorthand for flex-grow, flex-shrink and flex-basis.

Reference:
- https://www.w3.org/TR/css-flexbox-1/#flex-property
"""
if value:
if isinstance(value, str):
values = [val.strip() for val in value.split()]
elif isinstance(value, Sequence):
values = value
else:
raise ValueError('Unknown flex %s ' % value)
else:
raise ValueError('Unknown flex %s ' % value)

# We iteratively split by the first left hand space found and try to validate if that part
# is a valid <flex-grow> or <flex-shrink> or <flex-basis> (which can come in any order)

# We use this dictionary to store parsed values and check that values properties are not
# duplicated
flex_dict = {}
for idx, part in enumerate(values):
if idx > 2:
# Flex can have a maximum of 3 parts
raise ValueError('Flex property shorthand contains too many parts!')

flex_dict = _parse_flex_property_part(part, flex_dict)

return flex_dict
13 changes: 12 additions & 1 deletion colosseum/wrappers.py
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,7 @@ def __repr__(self):

def __str__(self):
parts = []
for key, value in self.to_dict().items():
for __, value in self.to_dict().items():
parts.append(str(value))

return ' '.join(parts)
Expand Down Expand Up @@ -235,3 +235,14 @@ def sort(self, cmp=None, key=None, reverse=False):

class Cursor(ImmutableList):
"""Immutable list to store cursor property."""


##############################################################################
# Flex
##############################################################################
class FlexFlow(Shorthand):
VALID_KEYS = ['flex_direction', 'flex_wrap']


class Flex(Shorthand):
VALID_KEYS = ['flex_grow', 'flex_shrink', 'flex_basis']