Skip to content

Commit a784f9f

Browse files
committed
Enable Flex declarations
1 parent abebfff commit a784f9f

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,
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
@@ -369,3 +369,128 @@ def border_bottom(value):
369369
def border_top(value):
370370
"""Parse border string into a dictionary of outline properties."""
371371
return border(value, direction='top')
372+
373+
374+
##############################################################################
375+
# Flex Flow
376+
##############################################################################
377+
def _parse_flex_flow_property_part(value, flex_flow_dict):
378+
"""Parse flex_flow shorthand property part for known properties."""
379+
from .constants import FLEX_DIRECTION_CHOICES, FLEX_WRAP_CHOICES
380+
381+
property_validators = {
382+
'flex_direction': FLEX_DIRECTION_CHOICES,
383+
'flex_wrap': FLEX_WRAP_CHOICES,
384+
}
385+
386+
for property_name, choices in property_validators.items():
387+
try:
388+
value = choices.validate(value)
389+
except (ValueError, ValidationError):
390+
continue
391+
392+
if property_name in flex_flow_dict:
393+
raise ValueError('Invalid duplicated property!')
394+
395+
flex_flow_dict[property_name] = value
396+
return flex_flow_dict
397+
398+
raise ValueError('Flex flow value "{value}" not valid!'.format(value=value))
399+
400+
401+
def flex_flow(value):
402+
"""
403+
Parse flex flow string into a dictionary of properties.
404+
405+
The font CSS property is a shorthand for flex-wrap and flex-direction.
406+
407+
Reference:
408+
- https://www.w3.org/TR/css-flexbox-1/#flex-flow-property
409+
"""
410+
if value:
411+
if isinstance(value, str):
412+
values = [val.strip() for val in value.split()]
413+
elif isinstance(value, Sequence):
414+
values = value
415+
else:
416+
raise ValueError('Unknown flex flow %s ' % value)
417+
else:
418+
raise ValueError('Unknown flex flow %s ' % value)
419+
420+
# We iteratively split by the first left hand space found and try to validate if that part
421+
# is a valid <flex-wrap> or <flex-direction> (which can come in any order)
422+
423+
# We use this dictionary to store parsed values and check that values properties are not
424+
# duplicated
425+
flex_flow_dict = {}
426+
for idx, part in enumerate(values):
427+
if idx > 1:
428+
# Flex flow can have a maximum of 2 parts
429+
raise ValueError('Flex flow property shorthand contains too many parts!')
430+
431+
flex_flow_dict = _parse_flex_flow_property_part(part, flex_flow_dict)
432+
433+
return flex_flow_dict
434+
435+
436+
##############################################################################
437+
# Flex
438+
##############################################################################
439+
def _parse_flex_property_part(value, flex_dict):
440+
"""Parse flex shorthand property part for known properties."""
441+
from .constants import FLEX_GROW_CHOICES, FLEX_SHRINK_CHOICES, FLEX_BASIS_CHOICES
442+
443+
property_validators = {
444+
'flex_grow': FLEX_GROW_CHOICES,
445+
'flex_shrink': FLEX_SHRINK_CHOICES,
446+
'flex_basis': FLEX_BASIS_CHOICES,
447+
}
448+
449+
for property_name, choices in property_validators.items():
450+
try:
451+
value = choices.validate(value)
452+
except (ValueError, ValidationError):
453+
continue
454+
455+
if property_name in flex_dict:
456+
raise ValueError('Invalid duplicated property!')
457+
458+
flex_dict[property_name] = value
459+
return flex_dict
460+
461+
raise ValueError('Flex value "{value}" not valid!'.format(value=value))
462+
463+
464+
def flex(value):
465+
"""
466+
Parse flex string into a dictionary of properties.
467+
468+
The font CSS property is a shorthand for flex-grow, flex-shrink and flex-basis.
469+
470+
Reference:
471+
- https://www.w3.org/TR/css-flexbox-1/#flex-property
472+
"""
473+
if value:
474+
if isinstance(value, str):
475+
values = [val.strip() for val in value.split()]
476+
elif isinstance(value, Sequence):
477+
values = value
478+
else:
479+
raise ValueError('Unknown flex flow %s ' % value)
480+
else:
481+
raise ValueError('Unknown flex flow %s ' % value)
482+
483+
# We iteratively split by the first left hand space found and try to validate if that part
484+
# is a valid <flex-grow> or <flex-shrink> or <flex-basis> (which can come in any order)
485+
486+
# We use this dictionary to store parsed values and check that values properties are not
487+
# duplicated
488+
flex_dict = {}
489+
for idx, part in enumerate(values):
490+
if idx > 2:
491+
# Flex can have a maximum of 3 parts
492+
raise ValueError('Flex property shorthand contains too many parts!')
493+
494+
flex_dict = _parse_flex_property_part(part, flex_dict)
495+
496+
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)
@@ -151,3 +151,14 @@ class BorderLeft(Shorthand):
151151

152152
class Border(Shorthand):
153153
VALID_KEYS = ['border_width', 'border_style', 'border_color']
154+
155+
156+
##############################################################################
157+
# Flex
158+
##############################################################################
159+
class FlexFlow(Shorthand):
160+
VALID_KEYS = ['flex_direction', 'flex_wrap']
161+
162+
163+
class Flex(Shorthand):
164+
VALID_KEYS = ['flex_grow', 'flex_shrink', 'flex_basis']

0 commit comments

Comments
 (0)