Skip to content

Commit f36f298

Browse files
committed
Enable Flex declarations
1 parent 61880b7 commit f36f298

3 files changed

Lines changed: 156 additions & 18 deletions

File tree

colosseum/declaration.py

Lines changed: 19 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
1-
from . import engine as css_engine
2-
from . import parser
1+
from . import engine as css_engine, parser
32
from .constants import ( # noqa
43
ALIGN_CONTENT_CHOICES, ALIGN_ITEMS_CHOICES, ALIGN_SELF_CHOICES, AUTO,
54
BACKGROUND_COLOR_CHOICES, BORDER_COLLAPSE_CHOICES, BORDER_COLOR_CHOICES,
@@ -15,16 +14,19 @@
1514
NOWRAP, ORDER_CHOICES, ORPHANS_CHOICES, OUTLINE_COLOR_CHOICES,
1615
OUTLINE_STYLE_CHOICES, OUTLINE_WIDTH_CHOICES, OVERFLOW_CHOICES,
1716
PADDING_CHOICES, PAGE_BREAK_AFTER_CHOICES, PAGE_BREAK_BEFORE_CHOICES,
18-
PAGE_BREAK_INSIDE_CHOICES, POSITION_CHOICES, QUOTES_CHOICES, ROW,
19-
SEPARATE, SHOW, SIZE_CHOICES, STATIC, STRETCH, TABLE_LAYOUT_CHOICES,
17+
PAGE_BREAK_INSIDE_CHOICES, POSITION_CHOICES, QUOTES_CHOICES, ROW, SEPARATE,
18+
SHOW, SIZE_CHOICES, STATIC, STRETCH, TABLE_LAYOUT_CHOICES,
2019
TEXT_ALIGN_CHOICES, TEXT_DECORATION_CHOICES, TEXT_INDENT_CHOICES,
2120
TEXT_TRANSFORM_CHOICES, TOP, TRANSPARENT, UNICODE_BIDI_CHOICES,
2221
VISIBILITY_CHOICES, VISIBLE, WHITE_SPACE_CHOICES, WIDOWS_CHOICES,
2322
WORD_SPACING_CHOICES, Z_INDEX_CHOICES, OtherProperty,
2423
TextAlignInitialValue, default, CURSOR_CHOICES,
2524
)
2625
from .exceptions import ValidationError
27-
from .wrappers import Border, BorderBottom, BorderLeft, BorderRight, BorderTop, Outline
26+
from .wrappers import ( # noqa
27+
Border, BorderBottom, BorderLeft, BorderRight, BorderTop, Flex, FlexFlow,
28+
Outline
29+
)
2830

2931
_CSS_PROPERTIES = set()
3032

@@ -424,36 +426,36 @@ def __init__(self, **style):
424426

425427
# 5. Ordering and orientation ########################################
426428
# 5.1 Flex flow direction
427-
# flex_direction = validated_property('flex_direction', choices=FLEX_DIRECTION_CHOICES, initial=ROW)
429+
flex_direction = validated_property('flex_direction', choices=FLEX_DIRECTION_CHOICES, initial=ROW)
428430

429431
# 5.2 Flex line wrapping
430-
# flex_wrap = validated_property('flex_wrap', choices=FLEX_WRAP_CHOICES, initial=NOWRAP)
432+
flex_wrap = validated_property('flex_wrap', choices=FLEX_WRAP_CHOICES, initial=NOWRAP)
431433

432434
# 5.3 Flex direction and wrap
433-
# flex_flow =
435+
flex_flow = validated_shorthand_property('flex_flow', parser=parser.flex_flow, wrapper=FlexFlow)
434436

435437
# 5.4 Display order
436-
# order = validated_property('order', choices=ORDER_CHOICES, initial=0)
438+
order = validated_property('order', choices=ORDER_CHOICES, initial=0)
437439

438440
# 7. Flexibility #####################################################
439441
# 7.2 Components of flexibility
440-
# flex_grow = validated_property('flex_grow', choices=FLEX_GROW_CHOICES, initial=0)
441-
# flex_shrink = validated_property('flex_shrink', choices=FLEX_SHRINK_CHOICES, initial=1)
442-
# flex_basis = validated_property('flex_basis', choices=FLEX_BASIS_CHOICES, initial=AUTO)
442+
flex_grow = validated_property('flex_grow', choices=FLEX_GROW_CHOICES, initial=0)
443+
flex_shrink = validated_property('flex_shrink', choices=FLEX_SHRINK_CHOICES, initial=1)
444+
flex_basis = validated_property('flex_basis', choices=FLEX_BASIS_CHOICES, initial=AUTO)
443445

444446
# 7.1 The 'flex' shorthand
445-
# flex =
447+
flex = validated_shorthand_property('flex', parser=parser.flex, wrapper=Flex)
446448

447449
# 8. Alignment #######################################################
448450
# 8.2 Axis alignment
449-
# justify_content = validated_property('justify_content', choices=JUSTIFY_CONTENT_CHOICES, initial=FLEX_START)
451+
justify_content = validated_property('justify_content', choices=JUSTIFY_CONTENT_CHOICES, initial=FLEX_START)
450452

451453
# 8.3 Cros-axis alignment
452-
# align_items = validated_property('align_items', choices=ALIGN_ITEMS_CHOICES, initial=STRETCH)
453-
# align_self = validated_property('align_self', choices=ALIGN_SELF_CHOICES, initial=AUTO)
454+
align_items = validated_property('align_items', choices=ALIGN_ITEMS_CHOICES, initial=STRETCH)
455+
align_self = validated_property('align_self', choices=ALIGN_SELF_CHOICES, initial=AUTO)
454456

455457
# 8.4 Packing flex lines
456-
# align_content = validated_property('align_content', choices=ALIGN_CONTENT_CHOICES, initial=STRETCH)
458+
align_content = validated_property('align_content', choices=ALIGN_CONTENT_CHOICES, initial=STRETCH)
457459

458460
######################################################################
459461
# Grid properties

colosseum/parser.py

Lines changed: 125 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -445,3 +445,128 @@ def cursor(values):
445445
raise ValueError('Value {value} is not a valid cursor value'.format(value=value))
446446

447447
return Cursor(validated_values)
448+
449+
450+
##############################################################################
451+
# Flex Flow
452+
##############################################################################
453+
def _parse_flex_flow_property_part(value, flex_flow_dict):
454+
"""Parse flex_flow shorthand property part for known properties."""
455+
from .constants import FLEX_DIRECTION_CHOICES, FLEX_WRAP_CHOICES
456+
457+
property_validators = {
458+
'flex_direction': FLEX_DIRECTION_CHOICES,
459+
'flex_wrap': FLEX_WRAP_CHOICES,
460+
}
461+
462+
for property_name, choices in property_validators.items():
463+
try:
464+
value = choices.validate(value)
465+
except (ValueError, ValidationError):
466+
continue
467+
468+
if property_name in flex_flow_dict:
469+
raise ValueError('Invalid duplicated property!')
470+
471+
flex_flow_dict[property_name] = value
472+
return flex_flow_dict
473+
474+
raise ValueError('Flex flow value "{value}" not valid!'.format(value=value))
475+
476+
477+
def flex_flow(value):
478+
"""
479+
Parse flex flow string into a dictionary of properties.
480+
481+
The font CSS property is a shorthand for flex-wrap and flex-direction.
482+
483+
Reference:
484+
- https://www.w3.org/TR/css-flexbox-1/#flex-flow-property
485+
"""
486+
if value:
487+
if isinstance(value, str):
488+
values = [val.strip() for val in value.split()]
489+
elif isinstance(value, Sequence):
490+
values = value
491+
else:
492+
raise ValueError('Unknown flex flow %s ' % value)
493+
else:
494+
raise ValueError('Unknown flex flow %s ' % value)
495+
496+
# We iteratively split by the first left hand space found and try to validate if that part
497+
# is a valid <flex-wrap> or <flex-direction> (which can come in any order)
498+
499+
# We use this dictionary to store parsed values and check that values properties are not
500+
# duplicated
501+
flex_flow_dict = {}
502+
for idx, part in enumerate(values):
503+
if idx > 1:
504+
# Flex flow can have a maximum of 2 parts
505+
raise ValueError('Flex flow property shorthand contains too many parts!')
506+
507+
flex_flow_dict = _parse_flex_flow_property_part(part, flex_flow_dict)
508+
509+
return flex_flow_dict
510+
511+
512+
##############################################################################
513+
# Flex
514+
##############################################################################
515+
def _parse_flex_property_part(value, flex_dict):
516+
"""Parse flex shorthand property part for known properties."""
517+
from .constants import FLEX_GROW_CHOICES, FLEX_SHRINK_CHOICES, FLEX_BASIS_CHOICES
518+
519+
property_validators = {
520+
'flex_grow': FLEX_GROW_CHOICES,
521+
'flex_shrink': FLEX_SHRINK_CHOICES,
522+
'flex_basis': FLEX_BASIS_CHOICES,
523+
}
524+
525+
for property_name, choices in property_validators.items():
526+
try:
527+
value = choices.validate(value)
528+
except (ValueError, ValidationError):
529+
continue
530+
531+
if property_name in flex_dict:
532+
raise ValueError('Invalid duplicated property!')
533+
534+
flex_dict[property_name] = value
535+
return flex_dict
536+
537+
raise ValueError('Flex value "{value}" not valid!'.format(value=value))
538+
539+
540+
def flex(value):
541+
"""
542+
Parse flex string into a dictionary of properties.
543+
544+
The font CSS property is a shorthand for flex-grow, flex-shrink and flex-basis.
545+
546+
Reference:
547+
- https://www.w3.org/TR/css-flexbox-1/#flex-property
548+
"""
549+
if value:
550+
if isinstance(value, str):
551+
values = [val.strip() for val in value.split()]
552+
elif isinstance(value, Sequence):
553+
values = value
554+
else:
555+
raise ValueError('Unknown flex %s ' % value)
556+
else:
557+
raise ValueError('Unknown flex %s ' % value)
558+
559+
# We iteratively split by the first left hand space found and try to validate if that part
560+
# is a valid <flex-grow> or <flex-shrink> or <flex-basis> (which can come in any order)
561+
562+
# We use this dictionary to store parsed values and check that values properties are not
563+
# duplicated
564+
flex_dict = {}
565+
for idx, part in enumerate(values):
566+
if idx > 2:
567+
# Flex can have a maximum of 3 parts
568+
raise ValueError('Flex property shorthand contains too many parts!')
569+
570+
flex_dict = _parse_flex_property_part(part, flex_dict)
571+
572+
return flex_dict

colosseum/wrappers.py

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -114,7 +114,7 @@ def __repr__(self):
114114

115115
def __str__(self):
116116
parts = []
117-
for key, value in self.to_dict().items():
117+
for __, value in self.to_dict().items():
118118
parts.append(str(value))
119119

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

236236
class Cursor(ImmutableList):
237237
"""Immutable list to store cursor property."""
238+
239+
240+
##############################################################################
241+
# Flex
242+
##############################################################################
243+
class FlexFlow(Shorthand):
244+
VALID_KEYS = ['flex_direction', 'flex_wrap']
245+
246+
247+
class Flex(Shorthand):
248+
VALID_KEYS = ['flex_grow', 'flex_shrink', 'flex_basis']

0 commit comments

Comments
 (0)