glimmer-dsl-web 0.4.2 → 0.4.3
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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +7 -0
- data/README.md +283 -56
- data/VERSION +1 -1
- data/glimmer-dsl-web.gemspec +3 -2
- data/lib/glimmer/data_binding/element_binding.rb +10 -4
- data/lib/glimmer/dsl/web/class_name_inclusion_data_binding.rb +21 -0
- data/lib/glimmer/dsl/web/dsl.rb +2 -0
- data/lib/glimmer/web/component.rb +8 -2
- data/lib/glimmer/web/element_proxy.rb +29 -2
- data/lib/glimmer-dsl-web/samples/hello/hello_style.rb +24 -25
- data/lib/glimmer-dsl-web/samples/regular/todo_mvc/views/edit_todo_input.rb +19 -10
- data/lib/glimmer-dsl-web/samples/regular/todo_mvc/views/new_todo_form.rb +8 -8
- data/lib/glimmer-dsl-web/samples/regular/todo_mvc/views/new_todo_input.rb +8 -5
- data/lib/glimmer-dsl-web/samples/regular/todo_mvc/views/todo_filters.rb +64 -51
- data/lib/glimmer-dsl-web/samples/regular/todo_mvc/views/todo_input.rb +14 -14
- data/lib/glimmer-dsl-web/samples/regular/todo_mvc/views/todo_list.rb +33 -37
- data/lib/glimmer-dsl-web/samples/regular/todo_mvc/views/todo_list_item.rb +62 -59
- data/lib/glimmer-dsl-web/samples/regular/todo_mvc/views/todo_mvc_footer.rb +9 -9
- data/lib/glimmer-dsl-web/samples/regular/todo_mvc.rb +20 -20
- metadata +2 -1
@@ -83,9 +83,8 @@ class StyledButton
|
|
83
83
|
button {
|
84
84
|
inner_text <= [button_model, :text, computed_by: :pushed]
|
85
85
|
|
86
|
-
class_name <= [button_model, :pushed
|
87
|
-
|
88
|
-
]
|
86
|
+
class_name(:pushed) <= [button_model, :pushed]
|
87
|
+
class_name(:pulled) <= [button_model, :pushed, on_read: :!]
|
89
88
|
|
90
89
|
style(:width) <= [button_model, :width, on_read: :px]
|
91
90
|
style(:height) <= [button_model, :height, on_read: :px]
|
@@ -99,22 +98,22 @@ class StyledButton
|
|
99
98
|
}
|
100
99
|
}
|
101
100
|
|
102
|
-
style {
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
margin
|
101
|
+
style {
|
102
|
+
r(component_element_selector) {
|
103
|
+
font_family 'Courrier New, Courrier'
|
104
|
+
border_radius 5
|
105
|
+
border_width 17
|
106
|
+
margin 5
|
108
107
|
}
|
109
108
|
|
110
|
-
|
111
|
-
|
109
|
+
r("#{component_element_selector}.pulled") {
|
110
|
+
border_style :outset
|
112
111
|
}
|
113
112
|
|
114
|
-
|
115
|
-
|
113
|
+
r("#{component_element_selector}.pushed") {
|
114
|
+
border_style :inset
|
116
115
|
}
|
117
|
-
|
116
|
+
}
|
118
117
|
end
|
119
118
|
|
120
119
|
class StyledButtonRangeInput
|
@@ -172,22 +171,22 @@ class HelloStyle
|
|
172
171
|
}
|
173
172
|
}
|
174
173
|
|
175
|
-
style {
|
176
|
-
.styled-button-form {
|
177
|
-
padding
|
178
|
-
display
|
179
|
-
|
174
|
+
style {
|
175
|
+
r('.styled-button-form') {
|
176
|
+
padding 20
|
177
|
+
display 'inline-grid'
|
178
|
+
grid_template_columns 'auto auto'
|
180
179
|
}
|
181
180
|
|
182
|
-
.styled-button-form label, input {
|
183
|
-
display:
|
184
|
-
margin
|
181
|
+
r('.styled-button-form label, input') {
|
182
|
+
display :block
|
183
|
+
margin '5px 5px 5px 0'
|
185
184
|
}
|
186
185
|
|
187
|
-
|
188
|
-
display:
|
186
|
+
r("#{component_element_selector} .styled-button") {
|
187
|
+
display :block
|
189
188
|
}
|
190
|
-
|
189
|
+
}
|
191
190
|
end
|
192
191
|
|
193
192
|
Document.ready? do
|
@@ -6,11 +6,16 @@ class EditTodoInput < TodoInput
|
|
6
6
|
|
7
7
|
markup { # evaluated against instance as a smart default convention
|
8
8
|
input { |edit_input|
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
9
|
+
# Data-bind inclusion of `li` `class` `editing` unidirectionally to todo editing attribute,
|
10
|
+
# meaning inclusion of editing class is determined by todo editing boolean attribute.
|
11
|
+
# `after_read` hook will have `input` grab keyboard focus when editing todo.
|
12
|
+
class_name(:editing) <= [ todo, :editing,
|
13
|
+
after_read: -> { edit_input.focus if todo.editing? }
|
14
|
+
]
|
13
15
|
|
16
|
+
# Data-bind `input` `value` property bidirectionally to `todo` `task` attribute
|
17
|
+
# meaning make any changes to the `todo` `task` attribute value automatically update the `input` `value` property
|
18
|
+
# and any changes to the `input` `value` property by the user automatically update the `todo` `task` attribute value.
|
14
19
|
value <=> [todo, :task]
|
15
20
|
|
16
21
|
onkeyup do |event|
|
@@ -31,17 +36,21 @@ class EditTodoInput < TodoInput
|
|
31
36
|
style { # evaluated against class as a smart default convention (common to all instances)
|
32
37
|
todo_input_styles
|
33
38
|
|
34
|
-
|
35
|
-
position
|
39
|
+
r("*:has(> #{component_element_selector})") {
|
40
|
+
position :relative
|
36
41
|
}
|
37
42
|
|
38
|
-
|
39
|
-
position
|
40
|
-
display
|
43
|
+
r(component_element_selector) {
|
44
|
+
position :absolute
|
45
|
+
display :none
|
41
46
|
width 'calc(100% - 43px)'
|
42
47
|
padding '12px 16px'
|
43
48
|
margin '0 0 0 43px'
|
44
|
-
top
|
49
|
+
top 0
|
50
|
+
}
|
51
|
+
|
52
|
+
r("#{component_element_selector}.editing") {
|
53
|
+
display :block
|
45
54
|
}
|
46
55
|
}
|
47
56
|
end
|
@@ -14,16 +14,16 @@ class NewTodoForm
|
|
14
14
|
}
|
15
15
|
|
16
16
|
style {
|
17
|
-
|
17
|
+
r('.header h1') {
|
18
18
|
color '#b83f45'
|
19
|
-
font_size
|
19
|
+
font_size 80
|
20
20
|
font_weight '200'
|
21
|
-
position
|
22
|
-
text_align
|
23
|
-
_webkit_text_rendering
|
24
|
-
_moz_text_rendering
|
25
|
-
text_rendering
|
26
|
-
top
|
21
|
+
position :absolute
|
22
|
+
text_align :center
|
23
|
+
_webkit_text_rendering :optimizeLegibility
|
24
|
+
_moz_text_rendering :optimizeLegibility
|
25
|
+
text_rendering :optimizeLegibility
|
26
|
+
top -140
|
27
27
|
width '100%'
|
28
28
|
}
|
29
29
|
}
|
@@ -5,6 +5,9 @@ class NewTodoInput < TodoInput
|
|
5
5
|
|
6
6
|
markup { # evaluated against instance as a smart convention
|
7
7
|
input(placeholder: "What needs to be done?", autofocus: "") {
|
8
|
+
# Data-bind `input` `value` property bidirectionally to `presenter.new_todo` `task` attribute
|
9
|
+
# meaning make any changes to the new todo task automatically update the input value
|
10
|
+
# and any changes to the input value by the user automatically update the new todo task value
|
8
11
|
value <=> [presenter.new_todo, :task]
|
9
12
|
|
10
13
|
onkeyup do |event|
|
@@ -16,16 +19,16 @@ class NewTodoInput < TodoInput
|
|
16
19
|
style { # evaluated against class as a smart convention (common to all instances)
|
17
20
|
todo_input_styles
|
18
21
|
|
19
|
-
|
22
|
+
r(component_element_selector) { # NewTodoInput has component_element_class as 'new-todo-input'
|
20
23
|
padding '16px 16px 16px 60px'
|
21
|
-
height
|
22
|
-
border
|
24
|
+
height 65
|
25
|
+
border :none
|
23
26
|
background 'rgba(0, 0, 0, 0.003)'
|
24
27
|
box_shadow 'inset 0 -2px 1px rgba(0,0,0,0.03)'
|
25
28
|
}
|
26
29
|
|
27
|
-
|
28
|
-
font_style
|
30
|
+
r("#{component_element_selector}::placeholder") {
|
31
|
+
font_style :italic
|
29
32
|
font_weight '400'
|
30
33
|
color 'rgba(0, 0, 0, 0.4)'
|
31
34
|
}
|
@@ -4,16 +4,21 @@ class TodoFilters
|
|
4
4
|
option :presenter
|
5
5
|
|
6
6
|
markup {
|
7
|
-
footer
|
8
|
-
style
|
9
|
-
|
10
|
-
|
7
|
+
footer {
|
8
|
+
# Data-bind `footer` `style` `display` unidirectionally to presenter todos,
|
9
|
+
# and on read, convert todos based on whether they are empty to 'none' or 'block'
|
10
|
+
style(:display) <= [ presenter, :todos,
|
11
|
+
on_read: ->(todos) { todos.empty? ? 'none' : 'block' }
|
12
|
+
]
|
11
13
|
|
12
14
|
span(class: 'todo-count') {
|
13
15
|
span('.strong') {
|
16
|
+
# Data-bind `span` `inner_text` unidirectionally to presenter active_todo_count
|
14
17
|
inner_text <= [presenter, :active_todo_count]
|
15
18
|
}
|
16
19
|
span {
|
20
|
+
# Data-bind `span` `inner_text` unidirectionally to presenter active_todo_count,
|
21
|
+
# and on read, convert active_todo_count to string that follows count number
|
17
22
|
inner_text <= [presenter, :active_todo_count,
|
18
23
|
on_read: -> (active_todo_count) { " item#{'s' if active_todo_count != 1} left" }
|
19
24
|
]
|
@@ -24,9 +29,11 @@ class TodoFilters
|
|
24
29
|
TodoPresenter::FILTERS.each do |filter|
|
25
30
|
li {
|
26
31
|
a(filter.to_s.capitalize, href: "#/#{filter unless filter == :all}") {
|
27
|
-
|
28
|
-
|
29
|
-
|
32
|
+
# Data-bind inclusion of `a` `class` `selected` unidirectionally to presenter filter attribute,
|
33
|
+
# and on read of presenter filter, convert to boolean value of whether selected class is included
|
34
|
+
class_name(:selected) <= [ presenter, :filter,
|
35
|
+
on_read: -> (presenter_filter) { presenter_filter == filter }
|
36
|
+
]
|
30
37
|
|
31
38
|
onclick do |event|
|
32
39
|
presenter.filter = filter
|
@@ -37,9 +44,9 @@ class TodoFilters
|
|
37
44
|
}
|
38
45
|
|
39
46
|
button('Clear completed', class: 'clear-completed') {
|
40
|
-
|
41
|
-
|
42
|
-
|
47
|
+
# Data-bind inclusion of `button` `class` `can-clear-completed` unidirectionally to presenter can_clear_completed attribute,
|
48
|
+
# meaning inclusion of can-clear-completed class is determined by presenter can_clear_completed boolean attribute.
|
49
|
+
class_name('can-clear-completed') <= [presenter, :can_clear_completed]
|
43
50
|
|
44
51
|
onclick do |event|
|
45
52
|
presenter.clear_completed
|
@@ -49,76 +56,82 @@ class TodoFilters
|
|
49
56
|
}
|
50
57
|
|
51
58
|
style {
|
52
|
-
|
59
|
+
r(component_element_selector) {
|
53
60
|
border_top '1px solid #e6e6e6'
|
54
|
-
font_size
|
55
|
-
height
|
61
|
+
font_size 15
|
62
|
+
height 20
|
56
63
|
padding '10px 15px'
|
57
|
-
text_align
|
64
|
+
text_align :center
|
65
|
+
display :none
|
58
66
|
}
|
59
67
|
|
60
|
-
|
61
|
-
bottom
|
68
|
+
r("#{component_element_selector}:before") {
|
69
|
+
bottom 0
|
62
70
|
box_shadow '0 1px 1px rgba(0,0,0,.2), 0 8px 0 -3px #f6f6f6, 0 9px 1px -3px rgba(0,0,0,.2), 0 16px 0 -6px #f6f6f6, 0 17px 2px -6px rgba(0,0,0,.2)'
|
63
71
|
content '""'
|
64
|
-
height
|
65
|
-
left
|
66
|
-
overflow
|
67
|
-
position
|
68
|
-
right
|
72
|
+
height 50
|
73
|
+
left 0
|
74
|
+
overflow :hidden
|
75
|
+
position :absolute
|
76
|
+
right 0
|
69
77
|
}
|
70
78
|
|
71
|
-
|
72
|
-
float
|
73
|
-
text_align
|
79
|
+
r('.todo-count') {
|
80
|
+
float :left
|
81
|
+
text_align :left
|
74
82
|
}
|
75
83
|
|
76
|
-
|
84
|
+
r('.todo-count .strong') {
|
77
85
|
font_weight '300'
|
78
86
|
}
|
79
87
|
|
80
|
-
|
81
|
-
left
|
82
|
-
list_style
|
83
|
-
margin
|
84
|
-
padding
|
85
|
-
position
|
86
|
-
right
|
88
|
+
r('.filters') {
|
89
|
+
left 0
|
90
|
+
list_style :none
|
91
|
+
margin 0
|
92
|
+
padding 0
|
93
|
+
position :absolute
|
94
|
+
right 0
|
87
95
|
}
|
88
96
|
|
89
|
-
|
90
|
-
display
|
97
|
+
r('.filters li') {
|
98
|
+
display :inline
|
91
99
|
}
|
92
100
|
|
93
|
-
|
101
|
+
r('.filters li a') {
|
94
102
|
border '1px solid transparent'
|
95
|
-
border_radius
|
96
|
-
color
|
97
|
-
margin
|
103
|
+
border_radius 3
|
104
|
+
color :inherit
|
105
|
+
margin 3
|
98
106
|
padding '3px 7px'
|
99
|
-
text_decoration
|
100
|
-
cursor
|
107
|
+
text_decoration :none
|
108
|
+
cursor :pointer
|
101
109
|
}
|
102
110
|
|
103
|
-
|
111
|
+
r('.filters li a.selected') {
|
104
112
|
border_color '#ce4646'
|
105
113
|
}
|
106
114
|
|
107
|
-
|
108
|
-
cursor
|
109
|
-
float
|
110
|
-
line_height
|
111
|
-
position
|
112
|
-
text_decoration
|
115
|
+
r('.clear-completed, html .clear-completed:active') {
|
116
|
+
cursor :pointer
|
117
|
+
float :right
|
118
|
+
line_height 19
|
119
|
+
position :relative
|
120
|
+
text_decoration :none
|
121
|
+
display :none
|
122
|
+
}
|
123
|
+
|
124
|
+
r('.clear-completed.can-clear-completed, html .clear-completed.can-clear-completed:active') {
|
125
|
+
display :block
|
113
126
|
}
|
114
127
|
|
115
128
|
media('(max-width: 430px)') {
|
116
|
-
|
117
|
-
height
|
129
|
+
r(component_element_selector) {
|
130
|
+
height 50
|
118
131
|
}
|
119
132
|
|
120
|
-
|
121
|
-
bottom
|
133
|
+
r('.filters') {
|
134
|
+
bottom 10
|
122
135
|
}
|
123
136
|
}
|
124
137
|
}
|
@@ -4,29 +4,29 @@ class TodoInput
|
|
4
4
|
|
5
5
|
class << self
|
6
6
|
def todo_input_styles
|
7
|
-
|
8
|
-
position
|
9
|
-
margin
|
7
|
+
r(component_element_selector) {
|
8
|
+
position :relative
|
9
|
+
margin 0
|
10
10
|
width '100%'
|
11
|
-
font_size
|
12
|
-
font_family
|
13
|
-
font_weight
|
14
|
-
line_height
|
15
|
-
color
|
16
|
-
padding
|
11
|
+
font_size 24
|
12
|
+
font_family :inherit
|
13
|
+
font_weight :inherit
|
14
|
+
line_height 1.4.em
|
15
|
+
color :inherit
|
16
|
+
padding 6
|
17
17
|
border '1px solid #999'
|
18
18
|
box_shadow 'inset 0 -1px 5px 0 rgba(0, 0, 0, 0.2)'
|
19
19
|
box_sizing 'border-box'
|
20
|
-
_webkit_font_smoothing
|
20
|
+
_webkit_font_smoothing :antialiased
|
21
21
|
}
|
22
22
|
|
23
|
-
|
24
|
-
background
|
23
|
+
r("#{component_element_selector}::selection") {
|
24
|
+
background :red
|
25
25
|
}
|
26
26
|
|
27
|
-
|
27
|
+
r("#{component_element_selector}:focus") {
|
28
28
|
box_shadow '0 0 2px 2px #cf7d7d'
|
29
|
-
outline
|
29
|
+
outline 0
|
30
30
|
}
|
31
31
|
end
|
32
32
|
end
|
@@ -15,10 +15,6 @@ class TodoList
|
|
15
15
|
|
16
16
|
markup {
|
17
17
|
main(class: 'main') {
|
18
|
-
style <= [ presenter, :todos,
|
19
|
-
on_read: ->(todos) { todos.empty? ? 'display: none;' : '' }
|
20
|
-
]
|
21
|
-
|
22
18
|
div(class: 'toggle-all-container') {
|
23
19
|
input(class: 'toggle-all', type: 'checkbox')
|
24
20
|
|
@@ -30,9 +26,9 @@ class TodoList
|
|
30
26
|
}
|
31
27
|
|
32
28
|
@todo_ul = ul {
|
33
|
-
|
34
|
-
|
35
|
-
|
29
|
+
# class name is data-bound unidirectionally to the presenter filter attribute,
|
30
|
+
# meaning it would automatically get set to its value whenever presenter.filter changes
|
31
|
+
class_name <= [presenter, :filter]
|
36
32
|
|
37
33
|
presenter.todos.each do |todo|
|
38
34
|
todo_list_item(presenter:, todo:)
|
@@ -42,61 +38,61 @@ class TodoList
|
|
42
38
|
}
|
43
39
|
|
44
40
|
style {
|
45
|
-
|
41
|
+
r('.main') {
|
46
42
|
border_top '1px solid #e6e6e6'
|
47
|
-
position
|
43
|
+
position :relative
|
48
44
|
z_index '2'
|
49
45
|
}
|
50
46
|
|
51
|
-
|
52
|
-
border
|
47
|
+
r('.toggle-all') {
|
48
|
+
border :none
|
53
49
|
bottom '100%'
|
54
|
-
height
|
55
|
-
opacity
|
56
|
-
position
|
50
|
+
height 1
|
51
|
+
opacity 0
|
52
|
+
position :absolute
|
57
53
|
right '100%'
|
58
|
-
width
|
54
|
+
width 1
|
59
55
|
}
|
60
56
|
|
61
|
-
|
62
|
-
align_items
|
63
|
-
display
|
64
|
-
font_size
|
65
|
-
height
|
66
|
-
justify_content
|
67
|
-
left
|
68
|
-
position
|
69
|
-
top
|
70
|
-
width
|
57
|
+
r('.toggle-all+label') {
|
58
|
+
align_items :center
|
59
|
+
display :flex
|
60
|
+
font_size 0
|
61
|
+
height 65
|
62
|
+
justify_content :center
|
63
|
+
left 0
|
64
|
+
position :absolute
|
65
|
+
top -65
|
66
|
+
width 45
|
71
67
|
}
|
72
68
|
|
73
|
-
|
69
|
+
r('.toggle-all+label:before') {
|
74
70
|
color '#949494'
|
75
71
|
content '"❯"'
|
76
72
|
display 'inline-block'
|
77
|
-
font_size
|
73
|
+
font_size 22
|
78
74
|
padding '10px 27px'
|
79
75
|
_webkit_transform 'rotate(90deg)'
|
80
76
|
transform 'rotate(90deg)'
|
81
77
|
}
|
82
78
|
|
83
|
-
|
79
|
+
r('.toggle-all:focus+label, .toggle:focus+label') {
|
84
80
|
box_shadow '0 0 2px 2px #cf7d7d'
|
85
|
-
outline
|
81
|
+
outline 0
|
86
82
|
}
|
87
83
|
|
88
|
-
|
89
|
-
list_style
|
90
|
-
margin
|
91
|
-
padding
|
84
|
+
r('.todo-list ul') {
|
85
|
+
list_style :none
|
86
|
+
margin 0
|
87
|
+
padding 0
|
92
88
|
}
|
93
89
|
|
94
|
-
|
95
|
-
display
|
90
|
+
r('.todo-list ul.active li.completed') {
|
91
|
+
display :none
|
96
92
|
}
|
97
93
|
|
98
|
-
|
99
|
-
display
|
94
|
+
r('.todo-list ul.completed li.active') {
|
95
|
+
display :none
|
100
96
|
}
|
101
97
|
}
|
102
98
|
end
|