webwidgets 1.1.0__py3-none-any.whl → 1.1.1__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- webwidgets/__init__.py +3 -1
- webwidgets/compilation/css/css.py +1 -1
- webwidgets/compilation/css/css_rule.py +3 -1
- webwidgets/compilation/css/sections/preamble.py +7 -4
- webwidgets/compilation/html/html_node.py +27 -27
- webwidgets/utility/__init__.py +2 -0
- webwidgets/utility/enums.py +18 -0
- webwidgets/utility/sizes/__init__.py +14 -0
- webwidgets/utility/sizes/size.py +92 -0
- webwidgets/utility/sizes/sizes.py +31 -0
- webwidgets/utility/validation.py +34 -3
- webwidgets/widgets/containers/__init__.py +1 -1
- webwidgets/widgets/containers/box.py +79 -11
- webwidgets/widgets/containers/container.py +7 -2
- webwidgets/widgets/containers/page.py +1 -1
- {webwidgets-1.1.0.dist-info → webwidgets-1.1.1.dist-info}/METADATA +1 -1
- webwidgets-1.1.1.dist-info/RECORD +34 -0
- webwidgets-1.1.0.dist-info/RECORD +0 -30
- {webwidgets-1.1.0.dist-info → webwidgets-1.1.1.dist-info}/WHEEL +0 -0
- {webwidgets-1.1.0.dist-info → webwidgets-1.1.1.dist-info}/licenses/LICENSE +0 -0
webwidgets/__init__.py
CHANGED
|
@@ -10,9 +10,11 @@
|
|
|
10
10
|
#
|
|
11
11
|
# =======================================================================
|
|
12
12
|
|
|
13
|
-
__version__ = "1.1.
|
|
13
|
+
__version__ = "1.1.1" # Dynamically set by build backend
|
|
14
14
|
|
|
15
15
|
from . import compilation
|
|
16
16
|
from . import utility
|
|
17
|
+
from .utility.enums import *
|
|
18
|
+
from .utility.sizes.sizes import *
|
|
17
19
|
from .website import *
|
|
18
20
|
from .widgets import *
|
|
@@ -170,7 +170,7 @@ def compile_css(trees: Union[HTMLNode, List[HTMLNode]],
|
|
|
170
170
|
Every HTML node present in one or more of the input trees is included
|
|
171
171
|
in the :py:attr:`CompiledCSS.mapping` attribute, even if the node does
|
|
172
172
|
not have a style. Rules are alphabetically ordered by class name in the
|
|
173
|
-
mapping.
|
|
173
|
+
mapping and in the :py:attr:`CompiledCSS.core` rule section.
|
|
174
174
|
:rtype: CompiledCSS
|
|
175
175
|
"""
|
|
176
176
|
# Handling case of a single tree
|
|
@@ -13,7 +13,8 @@
|
|
|
13
13
|
from typing import Dict
|
|
14
14
|
from webwidgets.utility.indentation import get_indentation
|
|
15
15
|
from webwidgets.utility.representation import ReprMixin
|
|
16
|
-
from webwidgets.utility.validation import validate_css_identifier,
|
|
16
|
+
from webwidgets.utility.validation import validate_css_identifier, \
|
|
17
|
+
validate_css_selector, validate_css_value
|
|
17
18
|
|
|
18
19
|
|
|
19
20
|
class CSSRule(ReprMixin):
|
|
@@ -60,6 +61,7 @@ class CSSRule(ReprMixin):
|
|
|
60
61
|
css_code = self.selector + " {\n"
|
|
61
62
|
for property_name, value in self.declarations.items():
|
|
62
63
|
validate_css_identifier(property_name)
|
|
64
|
+
validate_css_value(value)
|
|
63
65
|
css_code += f"{indentation}{property_name}: {value};\n"
|
|
64
66
|
css_code += "}"
|
|
65
67
|
|
|
@@ -17,9 +17,9 @@ from webwidgets.compilation.css.css_rule import CSSRule
|
|
|
17
17
|
class Preamble(RuleSection):
|
|
18
18
|
"""A set of CSS rules that apply globally to all HTML elements.
|
|
19
19
|
|
|
20
|
-
The CSS preamble serves as a global default for multiple properties.
|
|
21
|
-
|
|
22
|
-
values to 0.
|
|
20
|
+
The CSS preamble serves as a global default for multiple properties. For
|
|
21
|
+
example, it defines the document's box model and sets all margin and
|
|
22
|
+
padding values to 0.
|
|
23
23
|
"""
|
|
24
24
|
|
|
25
25
|
def __init__(self):
|
|
@@ -33,7 +33,10 @@ class Preamble(RuleSection):
|
|
|
33
33
|
|
|
34
34
|
# Setting all margin and padding values to 0
|
|
35
35
|
"margin": "0",
|
|
36
|
-
"padding": "0"
|
|
36
|
+
"padding": "0",
|
|
37
|
+
|
|
38
|
+
# Sets the overflow policy to hidden
|
|
39
|
+
"overflow": "hidden"
|
|
37
40
|
})
|
|
38
41
|
],
|
|
39
42
|
title="Preamble"
|
|
@@ -63,6 +63,33 @@ class HTMLNode(ReprMixin):
|
|
|
63
63
|
f'{k}="{v}"' for k, v in sorted(self.attributes.items())
|
|
64
64
|
)
|
|
65
65
|
|
|
66
|
+
@property
|
|
67
|
+
def end_tag(self) -> str:
|
|
68
|
+
"""Returns the closing tag of the HTML node.
|
|
69
|
+
|
|
70
|
+
:return: A string containing the closing tag of the element.
|
|
71
|
+
:rtype: str
|
|
72
|
+
"""
|
|
73
|
+
return f"</{self._get_tag_name()}>"
|
|
74
|
+
|
|
75
|
+
@property
|
|
76
|
+
def start_tag(self) -> str:
|
|
77
|
+
"""Returns the opening tag of the HTML node, including any attributes.
|
|
78
|
+
|
|
79
|
+
Attributes are validated with :py:meth:`HTMLNode.validate_attributes`
|
|
80
|
+
before rendering.
|
|
81
|
+
|
|
82
|
+
:return: A string containing the opening tag of the element with its attributes.
|
|
83
|
+
:rtype: str
|
|
84
|
+
"""
|
|
85
|
+
# Rendering attributes
|
|
86
|
+
self.validate_attributes()
|
|
87
|
+
attributes = self._render_attributes()
|
|
88
|
+
maybe_space = ' ' if attributes else ''
|
|
89
|
+
|
|
90
|
+
# Building start tag
|
|
91
|
+
return f"<{self._get_tag_name()}{maybe_space}{attributes}>"
|
|
92
|
+
|
|
66
93
|
def add(self, child: 'HTMLNode') -> None:
|
|
67
94
|
"""Adds a child to the HTML node.
|
|
68
95
|
|
|
@@ -101,33 +128,6 @@ class HTMLNode(ReprMixin):
|
|
|
101
128
|
styles.update(child.get_styles())
|
|
102
129
|
return styles
|
|
103
130
|
|
|
104
|
-
@property
|
|
105
|
-
def start_tag(self) -> str:
|
|
106
|
-
"""Returns the opening tag of the HTML node, including any attributes.
|
|
107
|
-
|
|
108
|
-
Attributes are validated with :py:meth:`HTMLNode.validate_attributes`
|
|
109
|
-
before rendering.
|
|
110
|
-
|
|
111
|
-
:return: A string containing the opening tag of the element with its attributes.
|
|
112
|
-
:rtype: str
|
|
113
|
-
"""
|
|
114
|
-
# Rendering attributes
|
|
115
|
-
self.validate_attributes()
|
|
116
|
-
attributes = self._render_attributes()
|
|
117
|
-
maybe_space = ' ' if attributes else ''
|
|
118
|
-
|
|
119
|
-
# Building start tag
|
|
120
|
-
return f"<{self._get_tag_name()}{maybe_space}{attributes}>"
|
|
121
|
-
|
|
122
|
-
@property
|
|
123
|
-
def end_tag(self) -> str:
|
|
124
|
-
"""Returns the closing tag of the HTML node.
|
|
125
|
-
|
|
126
|
-
:return: A string containing the closing tag of the element.
|
|
127
|
-
:rtype: str
|
|
128
|
-
"""
|
|
129
|
-
return f"</{self._get_tag_name()}>"
|
|
130
|
-
|
|
131
131
|
def to_html(self, collapse_empty: bool = True,
|
|
132
132
|
indent_size: int = 4, indent_level: int = 0,
|
|
133
133
|
force_one_line: bool = False, return_lines: bool = False,
|
webwidgets/utility/__init__.py
CHANGED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
# =======================================================================
|
|
2
|
+
#
|
|
3
|
+
# This file is part of WebWidgets, a Python package for designing web
|
|
4
|
+
# UIs.
|
|
5
|
+
#
|
|
6
|
+
# You should have received a copy of the MIT License along with
|
|
7
|
+
# WebWidgets. If not, see <https://opensource.org/license/mit>.
|
|
8
|
+
#
|
|
9
|
+
# Copyright(C) 2025, mlaasri
|
|
10
|
+
#
|
|
11
|
+
# =======================================================================
|
|
12
|
+
|
|
13
|
+
from enum import auto, Enum
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
class Direction(Enum):
|
|
17
|
+
HORIZONTAL = auto()
|
|
18
|
+
VERTICAL = auto()
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
# =======================================================================
|
|
2
|
+
#
|
|
3
|
+
# This file is part of WebWidgets, a Python package for designing web
|
|
4
|
+
# UIs.
|
|
5
|
+
#
|
|
6
|
+
# You should have received a copy of the MIT License along with
|
|
7
|
+
# WebWidgets. If not, see <https://opensource.org/license/mit>.
|
|
8
|
+
#
|
|
9
|
+
# Copyright(C) 2025, mlaasri
|
|
10
|
+
#
|
|
11
|
+
# =======================================================================
|
|
12
|
+
|
|
13
|
+
from .size import *
|
|
14
|
+
from .sizes import *
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
# =======================================================================
|
|
2
|
+
#
|
|
3
|
+
# This file is part of WebWidgets, a Python package for designing web
|
|
4
|
+
# UIs.
|
|
5
|
+
#
|
|
6
|
+
# You should have received a copy of the MIT License along with
|
|
7
|
+
# WebWidgets. If not, see <https://opensource.org/license/mit>.
|
|
8
|
+
#
|
|
9
|
+
# Copyright(C) 2025, mlaasri
|
|
10
|
+
#
|
|
11
|
+
# =======================================================================
|
|
12
|
+
|
|
13
|
+
from webwidgets.utility.representation import ReprMixin
|
|
14
|
+
from typing import Callable, Type, Union
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
class Size(ReprMixin):
|
|
18
|
+
"""Base class representing a length.
|
|
19
|
+
|
|
20
|
+
Sizes are specified by a numerical value and a CSS unit (e.g. `px`, `%`,
|
|
21
|
+
etc.). The value is provided upon creation and the unit is derived from the
|
|
22
|
+
class name of the :py:class:`Size` object.
|
|
23
|
+
"""
|
|
24
|
+
|
|
25
|
+
def __init__(self, value: Union[float, int]):
|
|
26
|
+
"""Creates a new :py:class:`Size` object with the given numerical
|
|
27
|
+
value.
|
|
28
|
+
|
|
29
|
+
:param value: The numerical value of the size.
|
|
30
|
+
:type value: Union[float, int]
|
|
31
|
+
"""
|
|
32
|
+
self.value = value
|
|
33
|
+
|
|
34
|
+
@property
|
|
35
|
+
def unit(self) -> str:
|
|
36
|
+
"""Returns the unit of the size's numerical value.
|
|
37
|
+
|
|
38
|
+
The unit of a size object is the name of its class in lowercase.
|
|
39
|
+
|
|
40
|
+
:return: The unit of the size.
|
|
41
|
+
:rtype: str
|
|
42
|
+
"""
|
|
43
|
+
return self.__class__.__name__.lower()
|
|
44
|
+
|
|
45
|
+
def to_css(self) -> str:
|
|
46
|
+
"""Compiles and returns the CSS representation of the :py:class:`Size`
|
|
47
|
+
object.
|
|
48
|
+
|
|
49
|
+
The CSS representation is obtained by concatenating the value of the
|
|
50
|
+
size with its unit (e.g. `"10px"`).
|
|
51
|
+
|
|
52
|
+
:return: The CSS representation of the size.
|
|
53
|
+
:rtype: str
|
|
54
|
+
"""
|
|
55
|
+
return str(self.value) + self.unit
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
class AbsoluteSize(Size):
|
|
59
|
+
"""A size whose unit is an absolute unit that does not depend on any
|
|
60
|
+
context. Examples include pixels (`"px"`) and centimeters (`"cm"`).
|
|
61
|
+
"""
|
|
62
|
+
pass
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
class RelativeSize(Size):
|
|
66
|
+
"""A size whose unit is relative to the size of other elements, such as the
|
|
67
|
+
size of a display or a font. Examples include percentages (`"%"`) and ems
|
|
68
|
+
(`"em"`).
|
|
69
|
+
"""
|
|
70
|
+
pass
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
def with_unit(unit: str) -> Callable[[Type[Size]], Type[Size]]:
|
|
74
|
+
"""Returns a decorator to override the unit of a Size subclass with the
|
|
75
|
+
given unit.
|
|
76
|
+
|
|
77
|
+
:param unit: The unit to be used for the Size subclass.
|
|
78
|
+
:type unit: str
|
|
79
|
+
:return: A decorator that overrides the unit of a Size subclass with the
|
|
80
|
+
given unit.
|
|
81
|
+
:rtype: Callable[[Type[Size]], Type[Size]]
|
|
82
|
+
"""
|
|
83
|
+
def _decorator(cls):
|
|
84
|
+
"""Decorator to override the unit of a Size subclass.
|
|
85
|
+
|
|
86
|
+
:param cls: A subclass of Size whose unit should be overridden.
|
|
87
|
+
:return: The given class with a new unit.
|
|
88
|
+
"""
|
|
89
|
+
cls.unit = property(
|
|
90
|
+
lambda _: unit, doc=f"Always returns '{unit}'.")
|
|
91
|
+
return cls
|
|
92
|
+
return _decorator
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
# =======================================================================
|
|
2
|
+
#
|
|
3
|
+
# This file is part of WebWidgets, a Python package for designing web
|
|
4
|
+
# UIs.
|
|
5
|
+
#
|
|
6
|
+
# You should have received a copy of the MIT License along with
|
|
7
|
+
# WebWidgets. If not, see <https://opensource.org/license/mit>.
|
|
8
|
+
#
|
|
9
|
+
# Copyright(C) 2025, mlaasri
|
|
10
|
+
#
|
|
11
|
+
# =======================================================================
|
|
12
|
+
|
|
13
|
+
from .size import AbsoluteSize, RelativeSize, with_unit
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
# Only exposing concrete size classes when using a wildcard import
|
|
17
|
+
__all__ = [
|
|
18
|
+
"Percent",
|
|
19
|
+
"Px"
|
|
20
|
+
]
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
@with_unit("%")
|
|
24
|
+
class Percent(RelativeSize):
|
|
25
|
+
"""A size expressed in percentage (`"%"`)."""
|
|
26
|
+
pass
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
class Px(AbsoluteSize):
|
|
30
|
+
"""A size expressed in pixels (`"px"`)."""
|
|
31
|
+
pass
|
webwidgets/utility/validation.py
CHANGED
|
@@ -10,7 +10,6 @@
|
|
|
10
10
|
#
|
|
11
11
|
# =======================================================================
|
|
12
12
|
|
|
13
|
-
from typing import *
|
|
14
13
|
import re
|
|
15
14
|
|
|
16
15
|
|
|
@@ -22,8 +21,8 @@ SPECIAL_SELECTORS = [
|
|
|
22
21
|
|
|
23
22
|
|
|
24
23
|
def validate_css_comment(comment: str) -> None:
|
|
25
|
-
"""
|
|
26
|
-
|
|
24
|
+
"""Checks if the given comment is a valid CSS comment according to the CSS
|
|
25
|
+
syntax rules and raises an exception if not.
|
|
27
26
|
|
|
28
27
|
This function just checks that the comment does not contain any closing
|
|
29
28
|
sequence `*/` as defined in the CSS Syntax Module Level 3, paragraph 4.3.2
|
|
@@ -124,6 +123,38 @@ def validate_css_selector(selector: str) -> None:
|
|
|
124
123
|
validate_css_identifier(selector[1:])
|
|
125
124
|
|
|
126
125
|
|
|
126
|
+
def validate_css_value(value: str) -> None:
|
|
127
|
+
"""Checks if the given value is a valid CSS property value and raises an
|
|
128
|
+
exception if not.
|
|
129
|
+
|
|
130
|
+
To be valid, the value must only contain:
|
|
131
|
+
- letters (`a-z`, `A-Z`)
|
|
132
|
+
- digits (`0-9`)
|
|
133
|
+
- dots (`.`)
|
|
134
|
+
- spaces (` `)
|
|
135
|
+
- hyphens (`-`)
|
|
136
|
+
- percent characters (`%`)
|
|
137
|
+
- hashtags (`#`)
|
|
138
|
+
|
|
139
|
+
Note that this function imposes stricter rules than the official CSS
|
|
140
|
+
specification - more precisely, than chapter 2 of the CSS Values and Units
|
|
141
|
+
Module Level 3 (see source:
|
|
142
|
+
https://www.w3.org/TR/css-values-3/#value-defs). For example, this function
|
|
143
|
+
does not allow functional notations like `calc()` whereas the specification
|
|
144
|
+
does.
|
|
145
|
+
|
|
146
|
+
:param value: The value to validate as a CSS property value.
|
|
147
|
+
:type value: str
|
|
148
|
+
:raises ValueError: If the value is not a valid CSS property value.
|
|
149
|
+
"""
|
|
150
|
+
if not re.match(r'^[a-zA-Z0-9. \-%#]+$', value):
|
|
151
|
+
invalid_chars = re.findall(r'[^a-zA-Z0-9. \-%#]', value)
|
|
152
|
+
raise ValueError("Invalid character(s) in CSS property value "
|
|
153
|
+
f"'{value}': {', '.join(invalid_chars)}\n"
|
|
154
|
+
"Only letters, digits, dots, spaces, hyphens, "
|
|
155
|
+
"percent characters, and hashtags are allowed.")
|
|
156
|
+
|
|
157
|
+
|
|
127
158
|
def validate_html_class(class_attribute: str) -> None:
|
|
128
159
|
"""Checks if the given HTML class attribute is valid and raises an
|
|
129
160
|
exception if not.
|
|
@@ -11,13 +11,12 @@
|
|
|
11
11
|
# =======================================================================
|
|
12
12
|
|
|
13
13
|
from .container import Container
|
|
14
|
-
from
|
|
14
|
+
from dataclasses import dataclass
|
|
15
|
+
from typing import Dict, Union
|
|
15
16
|
from webwidgets.compilation.html.html_tags import Div
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
HORIZONTAL = auto()
|
|
20
|
-
VERTICAL = auto()
|
|
17
|
+
from webwidgets.utility.enums import Direction
|
|
18
|
+
from webwidgets.utility.sizes.sizes import AbsoluteSize
|
|
19
|
+
from webwidgets.widgets.widget import Widget
|
|
21
20
|
|
|
22
21
|
|
|
23
22
|
class Box(Container):
|
|
@@ -34,8 +33,42 @@ class Box(Container):
|
|
|
34
33
|
"""
|
|
35
34
|
super().__init__()
|
|
36
35
|
self.direction = direction
|
|
36
|
+
self._properties: Dict[int, BoxItemProperties] = {}
|
|
37
|
+
|
|
38
|
+
def add(self, widget: Widget,
|
|
39
|
+
space: Union[int, float, AbsoluteSize] = 1) -> None:
|
|
40
|
+
"""Adds a widget to the box with an optional space coefficient.
|
|
41
|
+
|
|
42
|
+
This function overrides :py:meth:`Container.add` from the base class to
|
|
43
|
+
extend its functionality and save additional properties on each widget
|
|
44
|
+
added to the box.
|
|
45
|
+
|
|
46
|
+
:param widget: The widget to add to the box.
|
|
47
|
+
:type widget: Widget
|
|
48
|
+
:param space: The amount of space to allocate for the widget to live
|
|
49
|
+
in.
|
|
50
|
+
|
|
51
|
+
If a numeric value (int or float), it must be at least 1, and it is
|
|
52
|
+
construed as the weight to give to the widget during space
|
|
53
|
+
allocation within the entire box. For example, if widget A has a
|
|
54
|
+
space of 1 and widget B has a space of 2, B will be allocated twice
|
|
55
|
+
as much space as A, i.e. a total of 2/3 of the entire box if the
|
|
56
|
+
only widgets the box contains are A and B.
|
|
57
|
+
|
|
58
|
+
If an instance of :py:class:`AbsoluteSize`, it is construed as the
|
|
59
|
+
exact size to allocate for the widget. For example, if widget A has
|
|
60
|
+
a space of `Px(100)` (i.e. 100px) and widget B has a space of 1, A
|
|
61
|
+
will be allocated exactly 100px while B will be allocated all the
|
|
62
|
+
remaining space if the only widgets the box contains are A and B.
|
|
63
|
+
|
|
64
|
+
Note that this value controls the amount of free space available
|
|
65
|
+
for the widget to grow in, not the size of the widget itself.
|
|
66
|
+
:type space: Union[int, float, AbsoluteSize]
|
|
67
|
+
"""
|
|
68
|
+
super().add(widget=widget)
|
|
69
|
+
self._properties[id(widget)] = BoxItemProperties(space=space)
|
|
37
70
|
|
|
38
|
-
def build(self):
|
|
71
|
+
def build(self) -> Div:
|
|
39
72
|
"""Builds the HTML representation of the Box.
|
|
40
73
|
|
|
41
74
|
The box is constructed as a `<div>` element with a flexbox layout. Its
|
|
@@ -45,9 +78,13 @@ class Box(Container):
|
|
|
45
78
|
Each child widget is wrapped inside its own `<div>` element with a
|
|
46
79
|
`data-role` attribute of "box-item". The items are centered within
|
|
47
80
|
their own `<div>`.
|
|
81
|
+
|
|
82
|
+
:return: A :py:class:`Div` element representing the Box.
|
|
83
|
+
:rtype: Div
|
|
48
84
|
"""
|
|
49
|
-
# Building child nodes
|
|
85
|
+
# Building child nodes and retrieving their properties
|
|
50
86
|
nodes = [w.build() for w in self.widgets]
|
|
87
|
+
properties = [self._properties[id(w)] for w in self.widgets]
|
|
51
88
|
|
|
52
89
|
# Building box items that wrap around child nodes
|
|
53
90
|
items = [Div(
|
|
@@ -57,9 +94,8 @@ class Box(Container):
|
|
|
57
94
|
"display": "flex",
|
|
58
95
|
"flex-direction": "row",
|
|
59
96
|
"align-items": "center",
|
|
60
|
-
"justify-content": "center"
|
|
61
|
-
|
|
62
|
-
}) for node in nodes]
|
|
97
|
+
"justify-content": "center"
|
|
98
|
+
} | props.to_style()) for node, props in zip(nodes, properties)]
|
|
63
99
|
|
|
64
100
|
# Assembling the box
|
|
65
101
|
flex_dir = "row" if self.direction == Direction.HORIZONTAL else "column"
|
|
@@ -68,3 +104,35 @@ class Box(Container):
|
|
|
68
104
|
"flex-direction": flex_dir
|
|
69
105
|
})
|
|
70
106
|
return box
|
|
107
|
+
|
|
108
|
+
|
|
109
|
+
@dataclass
|
|
110
|
+
class BoxItemProperties:
|
|
111
|
+
"""A utility dataclass to store extra properties to apply to a widget
|
|
112
|
+
contained in a :py:class:`Box` during compilation.
|
|
113
|
+
"""
|
|
114
|
+
|
|
115
|
+
space: Union[int, float, AbsoluteSize]
|
|
116
|
+
|
|
117
|
+
def to_style(self) -> Dict[str, str]:
|
|
118
|
+
"""Converts the properties of the :py:class:`BoxItemProperties`
|
|
119
|
+
instance into a dictionary of CSS properties that can be added to the
|
|
120
|
+
style of an HTML node.
|
|
121
|
+
|
|
122
|
+
:return: A dictionary of CSS properties.
|
|
123
|
+
:rtype: Dict[str, str]
|
|
124
|
+
"""
|
|
125
|
+
# If a numeric value, the space serves as a relative weight
|
|
126
|
+
if isinstance(self.space, (int, float)):
|
|
127
|
+
return {
|
|
128
|
+
"flex-basis": "0",
|
|
129
|
+
"flex-grow": str(self.space),
|
|
130
|
+
"flex-shrink": str(self.space)
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
# If an AbsoluteSize object, the space is a fixed size
|
|
134
|
+
return {
|
|
135
|
+
"flex-basis": self.space.to_css(),
|
|
136
|
+
"flex-grow": "0",
|
|
137
|
+
"flex-shrink": "0"
|
|
138
|
+
}
|
|
@@ -27,7 +27,12 @@ class Container(Widget):
|
|
|
27
27
|
:type widgets: List[Widget]
|
|
28
28
|
"""
|
|
29
29
|
super().__init__()
|
|
30
|
-
self.
|
|
30
|
+
self._widgets = [] if widgets is None else widgets
|
|
31
|
+
|
|
32
|
+
@property
|
|
33
|
+
def widgets(self) -> List[Widget]:
|
|
34
|
+
"""Returns the list of widgets contained within the container."""
|
|
35
|
+
return self._widgets
|
|
31
36
|
|
|
32
37
|
def add(self, widget: Widget) -> None:
|
|
33
38
|
"""Adds a widget to the container.
|
|
@@ -35,4 +40,4 @@ class Container(Widget):
|
|
|
35
40
|
:param widget: The widget to add to the container.
|
|
36
41
|
:type widget: Widget
|
|
37
42
|
"""
|
|
38
|
-
self.
|
|
43
|
+
self._widgets.append(widget)
|
|
@@ -32,7 +32,7 @@ class Page(Container):
|
|
|
32
32
|
:param css_file_name: The name of the CSS file to link to the page if
|
|
33
33
|
the page elements contain any styles. Defaults to "styles.css".
|
|
34
34
|
:type css_file_name: str
|
|
35
|
-
:return:
|
|
35
|
+
:return: A :py:class:`RootNode` object representing the page.
|
|
36
36
|
:rtype: RootNode
|
|
37
37
|
"""
|
|
38
38
|
# Building nodes from the page's widgets
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
webwidgets/__init__.py,sha256=fkkQsGyTLNHc3pL-njm0KmAZRqDfvmwDhun0ZT7N92w,613
|
|
2
|
+
webwidgets/compilation/__init__.py,sha256=hb61nhmPTghIzuA_hun98xT5Ngv7QFAgMHD44g-9uOo,433
|
|
3
|
+
webwidgets/compilation/css/__init__.py,sha256=A4VUGyy92Vn32Km2VuJL5bBmLdovN6PDfv_DctRdzJk,534
|
|
4
|
+
webwidgets/compilation/css/css.py,sha256=v2GSyegop8JmE_9ITZ-2oc9P_8bE33-YWsjiO8FGaWI,9351
|
|
5
|
+
webwidgets/compilation/css/css_rule.py,sha256=8NKQwNfETc52KDrMoy_rJtie6si1SrdfnxKRBRjLJqM,3594
|
|
6
|
+
webwidgets/compilation/css/sections/__init__.py,sha256=qPLq_w0kIPGvIIXxsblF7iUdm9AOA-CUl06krTMnHHI,465
|
|
7
|
+
webwidgets/compilation/css/sections/css_section.py,sha256=LfQojXSYbsh9UcbqD4vn6heEO7qjGNrwy7Py5bsvy9U,4020
|
|
8
|
+
webwidgets/compilation/css/sections/preamble.py,sha256=zDU3JZpIYoc9Xynquc50awqhvYxNi0EbprbwCVScvoY,1355
|
|
9
|
+
webwidgets/compilation/css/sections/rule_section.py,sha256=BBeIJyVRz2ZeBxEC6VrEymXF6LjzE_GPu6X04A-lGF8,1456
|
|
10
|
+
webwidgets/compilation/html/__init__.py,sha256=h8eWh8BbjLZA1wIGAeOxyhZIUM1e36ZgMTwL5SQajHc,514
|
|
11
|
+
webwidgets/compilation/html/html_node.py,sha256=QJgUWpAsvJSd4C9FUAvtcCZWlCLA0fZK5A0c8_pbsWc,11697
|
|
12
|
+
webwidgets/compilation/html/html_tags.py,sha256=R13axcPAOnqRVPM8FP0k04QIW7gZMSJt3jlsv7Q-fXg,2276
|
|
13
|
+
webwidgets/utility/__init__.py,sha256=GDS2bOS36He7EAde1YAcSQ_P49zkKIPGIRP8NRCFJbs,547
|
|
14
|
+
webwidgets/utility/enums.py,sha256=RDgYT2S85DrhKL-3T7oHN20iW4vYoD8TKLsEmsO2OaE,495
|
|
15
|
+
webwidgets/utility/indentation.py,sha256=BaOQRqWdG7T5k_g1-ia9jewPFZjD3afjZH_Fc4NSVwo,906
|
|
16
|
+
webwidgets/utility/representation.py,sha256=lQ15v_DZOHBQKLM8pzRE1tuJkU_modhPTpWpSJ2lBCE,1061
|
|
17
|
+
webwidgets/utility/sanitizing.py,sha256=OKJRDqk-OXYCWeK6ie3GdfQvb49wTs93kd971mg5oK0,5770
|
|
18
|
+
webwidgets/utility/validation.py,sha256=ZKKEkhkdhuC7JxVG1_BKFBLT80DOGaSCOCo6ZJgzwmU,8239
|
|
19
|
+
webwidgets/utility/sizes/__init__.py,sha256=2tmSdXRBlIWuOfZUmToc0_gFiVKJIFUCh6H9B2Bf9rw,437
|
|
20
|
+
webwidgets/utility/sizes/size.py,sha256=UjffvXNNV4BhgyJ_OV_ZArYas7FP4Bhul_ujktsQbQM,2867
|
|
21
|
+
webwidgets/utility/sizes/sizes.py,sha256=DoKIruTw2RjuvH9MmM-CG5C2_WnmLt0mlAWphPstM6E,747
|
|
22
|
+
webwidgets/website/__init__.py,sha256=zp4N3CtY0SLNfDV9p2Y0tqbta-vFOX1PSJr7eQ9rQdk,471
|
|
23
|
+
webwidgets/website/compiled_website.py,sha256=lR_sabYtdWiRWicyxEFs4yxRUB_TbMowpsNz3CtqQBQ,1129
|
|
24
|
+
webwidgets/website/website.py,sha256=2vdIxYLXOu_otiF-KTOBigoic0aUWwgglfXAAZRzURg,3349
|
|
25
|
+
webwidgets/widgets/__init__.py,sha256=J2br7F-16URKvWshkJcc4nth27YQsaLrdVZu0xXx5CU,449
|
|
26
|
+
webwidgets/widgets/widget.py,sha256=NRyiy_vBStX2r-LBeJpqFy-AMw1aaqxrx4sz-GIdJnE,1034
|
|
27
|
+
webwidgets/widgets/containers/__init__.py,sha256=0y63aqzzJzC77oKOK1rcqQGDk710lkalc6vyZr7iJWo,473
|
|
28
|
+
webwidgets/widgets/containers/box.py,sha256=iwr-n09ePMICQLF4MZeAzRjBuPCdqHF2cFF8OLSH_oA,5435
|
|
29
|
+
webwidgets/widgets/containers/container.py,sha256=-UAnDEC0o-rP2PBF1ji8xUGRQYRnDvKmVSDaQH3_DYE,1317
|
|
30
|
+
webwidgets/widgets/containers/page.py,sha256=JQBV9U803nfiC20_4kJ4RkibqVeMKf30FZOGmii6YV4,2179
|
|
31
|
+
webwidgets-1.1.1.dist-info/METADATA,sha256=UBIZPHX_nOWMcxrnmWEgOcDJdzTuVK90DuX43JMhMi4,1607
|
|
32
|
+
webwidgets-1.1.1.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
|
33
|
+
webwidgets-1.1.1.dist-info/licenses/LICENSE,sha256=LISw1mw5eK6i8adFSlx6zltZxrJFwurngVdZAEU8g_I,1064
|
|
34
|
+
webwidgets-1.1.1.dist-info/RECORD,,
|
|
@@ -1,30 +0,0 @@
|
|
|
1
|
-
webwidgets/__init__.py,sha256=XGu3i9D0Zs9W12E62C5Yq-Aejh_GTlyz6197FAoxiME,549
|
|
2
|
-
webwidgets/compilation/__init__.py,sha256=hb61nhmPTghIzuA_hun98xT5Ngv7QFAgMHD44g-9uOo,433
|
|
3
|
-
webwidgets/compilation/css/__init__.py,sha256=A4VUGyy92Vn32Km2VuJL5bBmLdovN6PDfv_DctRdzJk,534
|
|
4
|
-
webwidgets/compilation/css/css.py,sha256=d7sxMOfT2s2sxG2O4LB4zSuknDb_fPcikKkiQk70vpc,9299
|
|
5
|
-
webwidgets/compilation/css/css_rule.py,sha256=QkeyVc9hmRwz0QY1avDugBpMM849VXcvJi18-c9h4x4,3530
|
|
6
|
-
webwidgets/compilation/css/sections/__init__.py,sha256=qPLq_w0kIPGvIIXxsblF7iUdm9AOA-CUl06krTMnHHI,465
|
|
7
|
-
webwidgets/compilation/css/sections/css_section.py,sha256=LfQojXSYbsh9UcbqD4vn6heEO7qjGNrwy7Py5bsvy9U,4020
|
|
8
|
-
webwidgets/compilation/css/sections/preamble.py,sha256=DwRwcKrVVeiypsHQn0FIQojpOQ3KUcrlaawxfipCue8,1251
|
|
9
|
-
webwidgets/compilation/css/sections/rule_section.py,sha256=BBeIJyVRz2ZeBxEC6VrEymXF6LjzE_GPu6X04A-lGF8,1456
|
|
10
|
-
webwidgets/compilation/html/__init__.py,sha256=h8eWh8BbjLZA1wIGAeOxyhZIUM1e36ZgMTwL5SQajHc,514
|
|
11
|
-
webwidgets/compilation/html/html_node.py,sha256=lOf1LEoVx23teWHfdlt5IpSv14cE6EI-aDyFGC_BXSU,11697
|
|
12
|
-
webwidgets/compilation/html/html_tags.py,sha256=R13axcPAOnqRVPM8FP0k04QIW7gZMSJt3jlsv7Q-fXg,2276
|
|
13
|
-
webwidgets/utility/__init__.py,sha256=Sl-dzpPPTHykkmLSfobhqHmlzUSPtvhaR4xtJy_tiOg,505
|
|
14
|
-
webwidgets/utility/indentation.py,sha256=BaOQRqWdG7T5k_g1-ia9jewPFZjD3afjZH_Fc4NSVwo,906
|
|
15
|
-
webwidgets/utility/representation.py,sha256=lQ15v_DZOHBQKLM8pzRE1tuJkU_modhPTpWpSJ2lBCE,1061
|
|
16
|
-
webwidgets/utility/sanitizing.py,sha256=OKJRDqk-OXYCWeK6ie3GdfQvb49wTs93kd971mg5oK0,5770
|
|
17
|
-
webwidgets/utility/validation.py,sha256=RB3JvMcVP6AKP1yrl44kFUQRzswtMa6ql7r2tqvrojE,6989
|
|
18
|
-
webwidgets/website/__init__.py,sha256=zp4N3CtY0SLNfDV9p2Y0tqbta-vFOX1PSJr7eQ9rQdk,471
|
|
19
|
-
webwidgets/website/compiled_website.py,sha256=lR_sabYtdWiRWicyxEFs4yxRUB_TbMowpsNz3CtqQBQ,1129
|
|
20
|
-
webwidgets/website/website.py,sha256=2vdIxYLXOu_otiF-KTOBigoic0aUWwgglfXAAZRzURg,3349
|
|
21
|
-
webwidgets/widgets/__init__.py,sha256=J2br7F-16URKvWshkJcc4nth27YQsaLrdVZu0xXx5CU,449
|
|
22
|
-
webwidgets/widgets/widget.py,sha256=NRyiy_vBStX2r-LBeJpqFy-AMw1aaqxrx4sz-GIdJnE,1034
|
|
23
|
-
webwidgets/widgets/containers/__init__.py,sha256=bKhkQHUfBMjYi7f0lPSBwP2EMn_M7n9VIh3He4gRqyc,484
|
|
24
|
-
webwidgets/widgets/containers/box.py,sha256=L5qYFsHWs0YzpAZ2Mv_i3pWzMp5od98tLjjf8KpnDhY,2351
|
|
25
|
-
webwidgets/widgets/containers/container.py,sha256=blpO2y9IiZ_4opwe9pqsSJPAZEN1P_ZRK4a27NpnMrg,1158
|
|
26
|
-
webwidgets/widgets/containers/page.py,sha256=sJ8QDmZ_6jzRFt4lyiAEPwjPvDTKm8EWOjz_Tq_cdjU,2180
|
|
27
|
-
webwidgets-1.1.0.dist-info/METADATA,sha256=b4hRl-cnHN3ndE_8RhOZPM_YFNtoJJfn6u8ovtFi8LA,1607
|
|
28
|
-
webwidgets-1.1.0.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
|
29
|
-
webwidgets-1.1.0.dist-info/licenses/LICENSE,sha256=LISw1mw5eK6i8adFSlx6zltZxrJFwurngVdZAEU8g_I,1064
|
|
30
|
-
webwidgets-1.1.0.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|