bemer 0.3.0 → 0.5.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: f081d85127046ac29d85d4dcffc832af6fc5c1e4ad49a2248b0502f3d0c17b26
4
- data.tar.gz: f0be9ccbdaf778a2ec2c4f01d533d12da6a687d3f152f007e3659c689bfc3985
3
+ metadata.gz: 84098253bdd2d8a9d177fddcf79e6a98af7c76af3e7fab7c717e380a799d12e1
4
+ data.tar.gz: 673f538a9fe0f1e34c649527cd1d8a3d08940601b18d16223308ebf9ef22dfcf
5
5
  SHA512:
6
- metadata.gz: c0155b1372465945e5090b8a205e155a26fe6af51291b8a47591dc2a36e697ff73e1943ec3acd1c183a0f320760f159b99e51f524acda1e1920d08e213eb0ebe
7
- data.tar.gz: a5ee0ef203901272ef8df243f9dfd1246451cf742ac98bc05ab73369ec42460de0fbd58dbf33e49ddb7eb255edf398c6885fb8044d5fb71765f61985921549ea
6
+ metadata.gz: 9a3fb72c68982a9d558192541b7de078d6ec98df923ddf048a2074742b62b553852d7f8486e1fd4786f690c6cf0ec392c33d15d82bbded151ccbec14168ed999
7
+ data.tar.gz: 6a9d7821d738c7a4137438708b8c4b5c9c707aa726cf4619647f2a69fd2c76d33d5c66a82b21a9cf059520f1dcae733b799fc318b96f75216db3379e47e53977
data/LICENSE-RU.txt CHANGED
@@ -1,6 +1,6 @@
1
1
  Лицензия MIT
2
2
 
3
- Copyright (c) 2017-2020 Александр Григорьев
3
+ Copyright (c) 2017-2023 Александр Григорьев
4
4
 
5
5
  Данная лицензия разрешает лицам, получившим копию данного программного
6
6
  обеспечения и сопутствующей документации (в дальнейшем именуемыми
data/LICENSE.txt CHANGED
@@ -1,6 +1,6 @@
1
1
  MIT License
2
2
 
3
- Copyright (c) 2017-2020 Alexander Grigorev
3
+ Copyright (c) 2017-2023 Alexander Grigorev
4
4
 
5
5
  Permission is hereby granted, free of charge, to any person obtaining a copy
6
6
  of this software and associated documentation files (the "Software"), to deal
data/README.md CHANGED
@@ -1,34 +1,273 @@
1
1
  # Bemer
2
2
 
3
- **ВАЖНО**. *Для работы с UI компонентами не обязательно использовать методологию БЭМ.*
3
+ 1. Build reusable UI components for Ruby on Rails applications.
4
+ 1. Develop Ruby on Rails applications using the `BEM` methodology.
4
5
 
5
- 1. Позволяет создавать переиспользуемые UI компоненты для приложений на Ruby on Rails.
6
- 1. Предоставляет функционал для разработки приложений на Ruby on Rails с использованием методологии БЭМ.
6
+ **IMPORTANT**. *Using the `BEM` methodology is optional.*
7
7
 
8
- ## Дополнительно
8
+ Additional resources:
9
9
 
10
- 1. Статья на Хабре - [Переиспользуемые UI компоненты в приложениях на Ruby on Rails](https://habrahabr.ru/post/352938/).
11
- 1. [bemer-bootstrap](https://github.com/vill/bemer-bootstrap) - переиспользуемые компоненты Bootstrap v3.
12
- 1. [Пример приложения](https://github.com/vill/bemer-example) с использованием `bemer` и [bemer-bootstrap](https://github.com/vill/bemer-bootstrap).
10
+ 1. Habr article in Russian - [Переиспользуемые UI компоненты в приложениях на Ruby on Rails](https://habrahabr.ru/post/352938/).
11
+ 1. [`bemer-simple_form`](https://github.com/vill/bemer-simple_form) - Add the `BEM` methodology to your `SimpleForm` forms.
12
+ 1. [`bemer-bootstrap`](https://github.com/vill/bemer-bootstrap) - Reusable UI components of `Bootstrap`.
13
+ 1. [Ruby on Rails application](https://github.com/vill/bemer-example) using `bemer` and [`bemer-bootstrap`](https://github.com/vill/bemer-bootstrap).
13
14
 
14
- ## Установка
15
+ *Please refer to the [README.ru.md](README.ru.md) file for instructions in Russian.*
15
16
 
16
- Добавить в `Gemfile`:
17
+
18
+ ## Installation
19
+
20
+ Add it to your Gemfile:
17
21
 
18
22
  ```ruby
19
- gem 'bemer', '~> 0.2.0'
23
+ gem 'bemer'
20
24
  ```
21
25
 
22
- Выполнить в терминале команду:
26
+ Run the following command to install it:
23
27
 
24
28
  $ bundle
25
29
 
26
- ## Использование
30
+ ## Configuration
31
+
32
+ See [configuration documentation](docs/%D0%9A%D0%BE%D0%BD%D1%84%D0%B8%D0%B3%D1%83%D1%80%D0%B0%D1%86%D0%B8%D1%8F.md) for details.
33
+
34
+ ```ruby
35
+ # config/initializers/bemer.rb
36
+
37
+ Bemer.setup do |config|
38
+ config.bem = true
39
+ config.modifier_name_separator = '--'
40
+ config.path = 'app/frontend/components' # or Webpacker.config.source_path
41
+ # config.default_path_prefix = lambda { |path, view|
42
+ # view.controller.class.name.split('::')[0].underscore
43
+ # }
44
+ end
45
+ ```
46
+
47
+ ## Integrations
48
+ ### Webpacker
49
+
50
+ ```yml
51
+ # config/webpacker.yml
52
+
53
+ default: &default
54
+ source_path: app/frontend/components
55
+ source_entry_path: ../packs
56
+ public_output_path: frontend/assets
57
+ # ...
58
+
59
+ development:
60
+ <<: *default
61
+ # ...
62
+
63
+ test:
64
+ <<: *default
65
+ # ...
66
+
67
+ production:
68
+ <<: *default
69
+ # ...
70
+ ```
71
+ #### File naming and folder structure
72
+ See [file naming and folder structure documentation](docs/%D0%A4%D0%B0%D0%B8%CC%86%D0%BB%D0%BE%D0%B2%D0%B0%D1%8F-%D1%81%D1%82%D1%80%D1%83%D0%BA%D1%82%D1%83%D1%80%D0%B0.md) for details.
73
+
74
+ ```
75
+ app/
76
+ ├── frontend/
77
+ | ├── components/
78
+ | | ├── common/
79
+ | | | ├── carousel/
80
+ | | | | ├── index.slim
81
+ | | | | ├── index.bemhtml.slim
82
+ | | | | ├── index.js
83
+ | | | | ├── index.scss
84
+ | | | | └── ...
85
+ | | | ├── form/
86
+ | | | | ├── error_messages_elem/
87
+ | | | | | ├── index.slim
88
+ | | | | | ├── index.js
89
+ | | | | | ├── index.scss
90
+ | | | | | └── ...
91
+ | | | | ├── locales/
92
+ | | | | | ├── en.yml
93
+ | | | | | └── ...
94
+ | | | | ├── index.slim
95
+ | | | | ├── base.rb
96
+ | | | | ├── index.js
97
+ | | | | ├── index.scss
98
+ | | | | └── ...
99
+ | | | └── ...
100
+ | | ├── admin_panel/
101
+ | | | └── ...
102
+ | | ├── landing/
103
+ | | | └── ...
104
+ | | ├── user_panel/
105
+ | | | └── ...
106
+ | | └── ...
107
+ | ├── packs/
108
+ | | ├── admin_panel/
109
+ | | | ├── application.js
110
+ | | | └── ...
111
+ | | ├── landing/
112
+ | | | ├── application.js
113
+ | | | └── ...
114
+ | | ├── user_panel/
115
+ | | | ├── application.js
116
+ | | | └── ...
117
+ | | └── ...
118
+ | └── ...
119
+ └── ...
120
+ ```
121
+
122
+ ### Sprockets
123
+
124
+ You do not need to do anything, but add additional assets to the asset load path if necessary:
125
+
126
+ ```ruby
127
+ # config/initializers/bemer.rb
128
+
129
+ Bemer.setup do |config|
130
+ config.asset_paths << Rails.root.join('some/asset/path')
131
+ end
132
+ ```
133
+
134
+ ### File naming and folder structure
135
+ See [file naming and folder structure documentation](docs/%D0%A4%D0%B0%D0%B8%CC%86%D0%BB%D0%BE%D0%B2%D0%B0%D1%8F-%D1%81%D1%82%D1%80%D1%83%D0%BA%D1%82%D1%83%D1%80%D0%B0.md) for details.
136
+
137
+ ```
138
+ app/
139
+ ├── assets/
140
+ | ├── javascripts/
141
+ | | ├── admin_panel/
142
+ | | | ├── application.js
143
+ | | | └── ...
144
+ | | ├── landing/
145
+ | | | ├── application.js
146
+ | | | └── ...
147
+ | | ├── user_panel/
148
+ | | | ├── application.js
149
+ | | | └── ...
150
+ | | └── ...
151
+ | ├── stylesheets/
152
+ | | ├── admin_panel/
153
+ | | | ├── application.scss
154
+ | | | └── ...
155
+ | | ├── landing/
156
+ | | | ├── application.scss
157
+ | | | └── ...
158
+ | | ├── user_panel/
159
+ | | | ├── application.scss
160
+ | | | └── ...
161
+ | | └── ...
162
+ | └── ...
163
+ ├── frontend/
164
+ | ├── components/
165
+ | | ├── common/
166
+ | | | ├── carousel/
167
+ | | | | ├── index.slim
168
+ | | | | ├── index.bemhtml.slim
169
+ | | | | ├── index.js
170
+ | | | | ├── index.scss
171
+ | | | | └── ...
172
+ | | | ├── form/
173
+ | | | | ├── error_messages_elem/
174
+ | | | | | ├── index.slim
175
+ | | | | | ├── index.js
176
+ | | | | | ├── index.scss
177
+ | | | | | └── ...
178
+ | | | | ├── locales/
179
+ | | | | | ├── en.yml
180
+ | | | | | └── ...
181
+ | | | | ├── index.slim
182
+ | | | | ├── base.rb
183
+ | | | | ├── index.js
184
+ | | | | ├── index.scss
185
+ | | | | └── ...
186
+ | | | └── ...
187
+ | | ├── admin_panel/
188
+ | | | └── ...
189
+ | | ├── landing/
190
+ | | | └── ...
191
+ | | ├── user_panel/
192
+ | | | └── ...
193
+ | | └── ...
194
+ | └── ...
195
+ └── ...
196
+ ```
197
+
198
+ ## Usage
199
+
200
+ ### Component to which `BEMHTML` templates cannot be applied
201
+
202
+ HTML structure of the [Carousel component from Bootstrap](https://getbootstrap.com/docs/4.3/components/carousel/#with-indicators):
203
+
204
+ ```slim
205
+ / app/frontend/components/common/carousel/index.slim
206
+
207
+ .carousel.slide data-ride="carousel" class=local_assigns[:cls]
208
+ ol.carousel-indicators
209
+ - image_urls.size.times do |i|
210
+ li data-target=".carousel" class=(:active if i.zero?) data-slide-to=i
211
+ .carousel-inner
212
+ - image_urls.each_with_index do |image_url, i|
213
+ .carousel-item class=(:active if i.zero?)
214
+ = image_tag image_url, class: 'd-block w-100'
215
+ a.carousel-control-prev data-slide="prev" data-target='.carousel' role="button"
216
+ span.carousel-control-prev-icon aria-hidden="true"
217
+ span.sr-only Previous
218
+ a.carousel-control-next data-slide="next" data-target='.carousel' role="button"
219
+ span.carousel-control-next-icon aria-hidden="true"
220
+ span.sr-only Next
221
+ ```
222
+ [Rendering](docs/%D0%A5%D0%B5%D0%BB%D0%BF%D0%B5%D1%80-render_component.md) the `carousel` component in any view or [other UI components](docs/%D0%A1%D0%BE%D0%B7%D0%B4%D0%B0%D0%BD%D0%B8%D0%B5-%D0%B8-%D0%B8%D1%81%D0%BF%D0%BE%D0%BB%D1%8C%D0%B7%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5-UI-%D0%BA%D0%BE%D0%BC%D0%BF%D0%BE%D0%BD%D0%B5%D0%BD%D1%82.md):
223
+ ```slim
224
+ = render_component :carousel, prefix: :common, image_urls: image_urls, cls: 'carousel-fade'
225
+ ```
226
+
227
+ ### Component to which `BEMHTML` templates can be applied
228
+
229
+ Tree structure of the [Carousel component from Bootstrap](https://getbootstrap.com/docs/4.3/components/carousel/#with-indicators):
230
+
231
+ ```slim
232
+ / app/frontend/components/common/carousel/index.slim
233
+
234
+ = define_component do |component|
235
+ = component.block :carousel, 'data-ride': :carousel, 'data-interval': false, cls: :slide do |carousel|
236
+ = carousel.elem :indicators, tag: :ol, cls: 'carousel-indicators'
237
+ - image_urls.size.times do |i|
238
+ = carousel.elem :indicator, tag: :li, 'data-slide-to': i, mods: (:active if i.zero?), 'data-target': '.carousel'
239
+ = carousel.elem :inner, cls: 'carousel-inner'
240
+ - image_urls.each_with_index do |image_url, i|
241
+ = carousel.elem :item, cls: 'carousel-item', mods: (:active if i.zero?)
242
+ = carousel.elem :image, tag: :img, cls: 'd-block w-100', src: image_url
243
+ = carousel.elem :control_prev, tag: :a, cls: 'carousel-control-prev', 'data-slide': :prev, role: :button, 'data-target': '.carousel'
244
+ span.carousel-control-prev-icon aria-hidden="true"
245
+ span.sr-only Previous
246
+ = carousel.elem :control_next, tag: :a, cls: 'carousel-control-next', 'data-slide': :next, role: :button, 'data-target': '.carousel'
247
+ span.carousel-control-next-icon aria-hidden="true"
248
+ span.sr-only Next
249
+ ```
250
+
251
+ [Default template](docs/%D0%A5%D0%B5%D0%BB%D0%BF%D0%B5%D1%80-define_templates.md):
252
+ ```slim
253
+ / app/frontend/components/common/carousel/index.bemhtml.slim
254
+
255
+ = define_templates do |template|
256
+ = template.elem(mods: :active).add_cls :active
257
+ ```
258
+
259
+ [Rendering](docs/%D0%A5%D0%B5%D0%BB%D0%BF%D0%B5%D1%80-render_component.md) the `carousel` component in any view or [other UI components](docs/%D0%A1%D0%BE%D0%B7%D0%B4%D0%B0%D0%BD%D0%B8%D0%B5-%D0%B8-%D0%B8%D1%81%D0%BF%D0%BE%D0%BB%D1%8C%D0%B7%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5-UI-%D0%BA%D0%BE%D0%BC%D0%BF%D0%BE%D0%BD%D0%B5%D0%BD%D1%82.md) using [`BEMHTML`](docs/BEMHTML.md) [templates](docs/%D0%A8%D0%B0%D0%B1%D0%BB%D0%BE%D0%BD%D1%8B.md):
260
+ ```slim
261
+ = render_component :carousel, prefix: :common, image_urls: image_urls do |template|
262
+ = template.block(:carousel).add_mix :carousel_fade
263
+ ```
264
+
265
+ ## Documentation in Russian
27
266
 
28
- 1. [Файловая структура](docs/%D0%A4%D0%B0%D0%B8%CC%86%D0%BB%D0%BE%D0%B2%D0%B0%D1%8F-%D1%81%D1%82%D1%80%D1%83%D0%BA%D1%82%D1%83%D1%80%D0%B0.md)
29
- 1. [Конфигурация](docs/%D0%9A%D0%BE%D0%BD%D1%84%D0%B8%D0%B3%D1%83%D1%80%D0%B0%D1%86%D0%B8%D1%8F.md)
30
- 1. [Создание и использование UI компонент](docs/%D0%A1%D0%BE%D0%B7%D0%B4%D0%B0%D0%BD%D0%B8%D0%B5-%D0%B8-%D0%B8%D1%81%D0%BF%D0%BE%D0%BB%D1%8C%D0%B7%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5-UI-%D0%BA%D0%BE%D0%BC%D0%BF%D0%BE%D0%BD%D0%B5%D0%BD%D1%82.md)
31
- 1. Хелперы для работы с компонентами
267
+ 1. [File naming and folder structure](docs/%D0%A4%D0%B0%D0%B8%CC%86%D0%BB%D0%BE%D0%B2%D0%B0%D1%8F-%D1%81%D1%82%D1%80%D1%83%D0%BA%D1%82%D1%83%D1%80%D0%B0.md)
268
+ 1. [Configuration](docs/%D0%9A%D0%BE%D0%BD%D1%84%D0%B8%D0%B3%D1%83%D1%80%D0%B0%D1%86%D0%B8%D1%8F.md)
269
+ 1. [Creating and using UI components](docs/%D0%A1%D0%BE%D0%B7%D0%B4%D0%B0%D0%BD%D0%B8%D0%B5-%D0%B8-%D0%B8%D1%81%D0%BF%D0%BE%D0%BB%D1%8C%D0%B7%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5-UI-%D0%BA%D0%BE%D0%BC%D0%BF%D0%BE%D0%BD%D0%B5%D0%BD%D1%82.md)
270
+ 1. Helpers for UI components
32
271
  1. [`define_component`](docs/%D0%A5%D0%B5%D0%BB%D0%BF%D0%B5%D1%80-define_component.md)
33
272
  1. [`define_templates`](docs/%D0%A5%D0%B5%D0%BB%D0%BF%D0%B5%D1%80-define_templates.md)
34
273
  1. [`render_component`](docs/%D0%A5%D0%B5%D0%BB%D0%BF%D0%B5%D1%80-render_component.md)
@@ -36,23 +275,25 @@ gem 'bemer', '~> 0.2.0'
36
275
  1. [`component_pack`](docs/%D0%A5%D0%B5%D0%BB%D0%BF%D0%B5%D1%80-component_pack.md)
37
276
  1. [`component_asset_path`](docs/%D0%A5%D0%B5%D0%BB%D0%BF%D0%B5%D1%80-component_asset_path.md)
38
277
  1. [`component_partial_path`](docs/%D0%A5%D0%B5%D0%BB%D0%BF%D0%B5%D1%80-component_partial_path.md)
39
- 1. Дополнительные хелперы для БЭМ методологии
278
+ 1. Additional helpers for the BEM methodology
279
+ 1. [`bem_attrs_for`](docs/%D0%A5%D0%B5%D0%BB%D0%BF%D0%B5%D1%80-bem_attrs_for.md)
40
280
  1. [`bem_mix`](docs/%D0%A5%D0%B5%D0%BB%D0%BF%D0%B5%D1%80-bem_mix.md)
41
281
  1. [`bem_mods`](docs/%D0%A5%D0%B5%D0%BB%D0%BF%D0%B5%D1%80-bem_mods.md)
42
282
  1. [`block_tag`](docs/%D0%A5%D0%B5%D0%BB%D0%BF%D0%B5%D1%80-block_tag.md)
43
283
  1. [`elem_tag`](docs/%D0%A5%D0%B5%D0%BB%D0%BF%D0%B5%D1%80-elem_tag.md)
44
284
  1. [BEMHTML](docs/BEMHTML.md)
45
- 1. [Шаблоны](docs/%D0%A8%D0%B0%D0%B1%D0%BB%D0%BE%D0%BD%D1%8B.md)
46
- 1. [Контекст узла](docs/%D0%9A%D0%BE%D0%BD%D1%82%D0%B5%D0%BA%D1%81%D1%82-%D1%83%D0%B7%D0%BB%D0%B0.md)
47
- 1. [Предикаты](docs/%D0%9F%D1%80%D0%B5%D0%B4%D0%B8%D0%BA%D0%B0%D1%82%D1%8B.md)
48
- 1. [Режимы](docs/%D0%A0%D0%B5%D0%B6%D0%B8%D0%BC%D1%8B.md)
285
+ 1. [Templates](docs/%D0%A8%D0%B0%D0%B1%D0%BB%D0%BE%D0%BD%D1%8B.md)
286
+ 1. [Node](docs/%D0%9A%D0%BE%D0%BD%D1%82%D0%B5%D0%BA%D1%81%D1%82-%D1%83%D0%B7%D0%BB%D0%B0.md)
287
+ 1. [Predicates](docs/%D0%9F%D1%80%D0%B5%D0%B4%D0%B8%D0%BA%D0%B0%D1%82%D1%8B.md)
288
+ 1. [Modes](docs/%D0%A0%D0%B5%D0%B6%D0%B8%D0%BC%D1%8B.md)
49
289
 
50
- ## Ссылки
290
+ ## Links
51
291
 
52
- 1. https://ru.bem.info/methodology/
53
- 1. https://github.com/bem/bem-xjst
54
- 1. https://github.com/bem-site/bem-forum-content-ru/issues
292
+ 1. BEM methodology - https://bem.info/methodology/
293
+ 1. Minimal stack for coding client-side JavaScript and templating - https://github.com/bem/bem-core
294
+ 1. Declarative template engine for the browser and server with regular JS syntax - https://github.com/bem/bem-xjst
295
+ 1. BEM Forum - https://bem.info/forum/
55
296
 
56
- ## Лицензия
297
+ ## License
57
298
 
58
- Copyright (c) 2017 - 2020 Александр Григорьев. Более подробную информацию о лицензии можно получить в файле [LICENSE.txt](LICENSE.txt).
299
+ Copyright (c) 2017-2023 Alexander Grigorev. See [LICENSE.txt](LICENSE.txt) for further details.
@@ -125,7 +125,7 @@ HTML тег изменить на `small` если текущая сущност
125
125
 
126
126
  ### Метод `name`
127
127
 
128
- **ВАЖНО**. *При формирование названия сущности, действуют [правила преобразования знаков нижнего подчеркивания `_` в тире `-` для `Symbol` и `String`](%D0%A5%D0%B5%D0%BB%D0%BF%D0%B5%D1%80-block_tag.md#%D0%9D%D0%B0%D0%B7%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5-%D1%81%D1%83%D1%89%D0%BD%D0%BE%D1%81%D1%82%D0%B8)*
128
+ **ВАЖНО**. *При формировании названия сущности, действуют [правила преобразования знаков нижнего подчеркивания `_` в тире `-` для `Symbol` и `String`](%D0%A5%D0%B5%D0%BB%D0%BF%D0%B5%D1%80-block_tag.md#%D0%9D%D0%B0%D0%B7%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5-%D1%81%D1%83%D1%89%D0%BD%D0%BE%D1%81%D1%82%D0%B8)*
129
129
 
130
130
  Возвращает название сущности.
131
131
 
@@ -0,0 +1,58 @@
1
+ # Хелпер bem_attrs_for
2
+
3
+ Хелпер `bem_attrs_for` генерирует `class` и `data-bem` атрибуты для указанной сущности.
4
+
5
+ ## Допустимые параметры
6
+
7
+ `cls` (синоним `class`), `js`, `mix` и `mods`, все остальные переданные параметры с названиями не из этого списка будут считаться атрибутами, за исключением: `bem`, `bem_cascade`, `content` и `tag`.
8
+
9
+
10
+ ## Использование
11
+
12
+ ```slim
13
+ = bem_attrs_for :block, :element
14
+ / => { class: "block__element i-bem", "data-bem": "{\"block__element\":{}}" }
15
+ ```
16
+
17
+ ```slim
18
+ = bem_attrs_for :block, :element, js: { some: :value }
19
+ / => { class: "block__element i-bem", "data-bem": "{\"block__element\":{\"some\":\"value\"}}" }
20
+ ```
21
+
22
+ ```slim
23
+ = simple_form_for :form, url: '#' do |f|
24
+ = f.input :numbers, collection: (1..5).map { |n| [n, n, bem_attrs_for(:form, :number, js: { value: n })] }
25
+ = f.button :submit
26
+ / =>
27
+ / <form novalidate="novalidate" class="form" action="#" accept-charset="UTF-8" method="post">
28
+ / <!-- ... -->
29
+ / <select class="form__numbers form__numbers--select form__numbers--required" name="form[numbers]" id="form_numbers">
30
+ / <option value=""></option>
31
+ / <option class="form__number i-bem" data-bem="{&quot;form__number&quot;:{&quot;value&quot;:1}}" value="1">1</option>
32
+ / <option class="form__number i-bem" data-bem="{&quot;form__number&quot;:{&quot;value&quot;:2}}" value="2">2</option>
33
+ / <option class="form__number i-bem" data-bem="{&quot;form__number&quot;:{&quot;value&quot;:3}}" value="3">3</option>
34
+ / <option class="form__number i-bem" data-bem="{&quot;form__number&quot;:{&quot;value&quot;:4}}" value="4">4</option>
35
+ / <option class="form__number i-bem" data-bem="{&quot;form__number&quot;:{&quot;value&quot;:5}}" value="5">5</option>
36
+ / </select>
37
+ / <!-- ... -->
38
+ / </form>
39
+ ```
40
+
41
+ ```slim
42
+ = simple_form_for :form, url: '#' do |f|
43
+ = f.input :numbers, collection: (1..5).map { |n| [n, n, bem_attrs_for(:form, :number, js: false)] }
44
+ = f.button :submit
45
+ / =>
46
+ / <form novalidate="novalidate" class="form" action="#" accept-charset="UTF-8" method="post">
47
+ / <!-- ... -->
48
+ / <select class="form__numbers form__numbers--select form__numbers--required" name="form[numbers]" id="form_numbers">
49
+ / <option value=""></option>
50
+ / <option class="form__number" value="1">1</option>
51
+ / <option class="form__number" value="2">2</option>
52
+ / <option class="form__number" value="3">3</option>
53
+ / <option class="form__number" value="4">4</option>
54
+ / <option class="form__number" value="5">5</option>
55
+ / </select>
56
+ / <!-- ... -->
57
+ / </form>
58
+ ```
@@ -50,12 +50,6 @@ bem_mix 'block_name' => 'elem_name' # => 'block_name__elem_name'
50
50
  bem_mix 'block_name', 'block_name__elem' # => 'block_name block_name__elem'
51
51
  ```
52
52
 
53
- эквивалентная запись:
54
-
55
- ```ruby
56
- bem_mix 'block_name block_name__elem' # => 'block_name block_name__elem'
57
- ```
58
-
59
53
  Пустые аргументы возвращают пустую строку
60
54
  ```ruby
61
55
  bem_mix nil, '', {} # => ''
@@ -16,7 +16,7 @@ block_tag js: true, bem: true # => <div></div>
16
16
  ## Название сущности
17
17
 
18
18
  При вызове `block_tag` первым аргументом передается название блока (указывать не обязательно) допустимые типы:
19
- 1. `Symbol` ВСЕ символы нижнего подчеркивания будут преобразованы в тире, при формирование css классов по методологии БЭМ
19
+ 1. `Symbol` ВСЕ символы нижнего подчеркивания будут преобразованы в тире, при формировании css классов по методологии БЭМ
20
20
  1. `String` возвращается без изменений
21
21
 
22
22
  ```ruby
@@ -81,7 +81,7 @@ block_tag :block, cls: ['cls_1', :cls_2], bem: false # => <div class="cls_1 cls-
81
81
  Добавляет содержимое для блока.
82
82
 
83
83
  ```ruby
84
- block_tag :block, content: 'Block content' # => <div>Block content</div>
84
+ block_tag :block, content: 'Block content' # => <div class="block">Block content</div>
85
85
  ```
86
86
  Если передан `Ruby &block`, тогда параметр `content` игнорируется:
87
87
 
@@ -169,6 +169,12 @@ block_tag :block, mix: [:mix_1, block_1: :elem], bem: true
169
169
 
170
170
  block_tag :block, mix: { block_1: :elem }, bem: true
171
171
  # => <div class="block block-1__elem"></div>
172
+
173
+ block_tag :block, mix: { block_1: :elem, mods: :enabled }
174
+ # => <div class="block block-1__elem block-1__elem--enabled"></div>
175
+
176
+ block_tag :block, js: true, mix: { block_1: :elem, js: { key: :value } }
177
+ # => <div class="block block-1__elem i-bem" data-bem="{"block":{},"block-1__elem":{"key":"value"}}"></div>
172
178
  ```
173
179
 
174
180
  ### Параметр `mods`
@@ -192,7 +198,7 @@ block_tag :block, mods: { size: :small }, bem: true
192
198
 
193
199
  ```ruby
194
200
  block_tag :block, tag: :span, content: 'Block content'
195
- # => <span>Block content</span>
201
+ # => <span class="block">Block content</span>
196
202
 
197
203
  block_tag :block, tag: '', content: 'Block content'
198
204
  # => 'Block content'
@@ -202,7 +208,7 @@ block_tag :block, tag: false, content: 'Block content'
202
208
 
203
209
  # Будет использован default_block_tag из конфига
204
210
  block_tag :block, tag: nil, content: 'Block content'
205
- # => <div>Block content</div>
211
+ # => <div class="block">Block content</div>
206
212
  ```
207
213
 
208
214
  ### Атрибуты
@@ -19,7 +19,7 @@ elem_tag '', :elem, js: true, bem: true # => <div></div>
19
19
  ## Название сущности
20
20
 
21
21
  При вызове `elem_tag` первым аргументом передается название блока (указывать не обязательно), вторым название элемента (указывать не обязательно) допустимые типы:
22
- 1. `Symbol` ВСЕ символы нижнего подчеркивания будут преобразованы в тире, при формирование css классов по БЭМ методологии
22
+ 1. `Symbol` ВСЕ символы нижнего подчеркивания будут преобразованы в тире, при формировании css классов по БЭМ методологии
23
23
  1. `String` возвращается без изменений
24
24
 
25
25
  ```ruby
@@ -18,8 +18,11 @@ module Bemer
18
18
  def initialize # rubocop:disable Metrics/MethodLength
19
19
  @asset_paths = []
20
20
  @bem = false
21
+ # https://github.com/brainspec/enumerize/blob/9dd68ca36d1efed6bc4cec8557a359f34f408d47/lib/enumerize/activerecord.rb#L24
22
+ # https://github.com/heartcombo/devise/blob/b52e642c0131f7b0d9f2dd24d8607a186f18223e/lib/devise.rb#L301
21
23
  # Gem::Version.new('0.4.1') > Gem::Version.new('0.10.1')
22
24
  # Здесь вроде также используют https://github.com/rspec/rspec-rails/blob/9b7ab39c027a8cb25e2ebe9e0e985756025b0549/Gemfile#L45
25
+ # https://github.com/JuanitoFatas/fast-ruby/blob/38f49f95fc7574d929de60b71791d09129c2588c/code/string/%3D%3D%3D-vs-%3D~-vs-match.rb#L20
23
26
  @can_use_new_matcher = RUBY_VERSION >= '2.4.0'
24
27
  @default_block_tag = :div
25
28
  @default_element_tag = :div
data/lib/bemer/entity.rb CHANGED
@@ -59,7 +59,7 @@ module Bemer
59
59
  @bem_cascade = options.delete(:bem_cascade)
60
60
  @css_classes = [options.delete(:class), options.delete(:cls)]
61
61
  @js = options.delete(:js)
62
- @mixins = MixinList.new(options.delete(:mix))
62
+ @mixins = Mixes.new(options.delete(:mix))
63
63
  @modifiers = ModifierList.new(block, element, options.delete(:mods))
64
64
  @tag = build_tag(options.delete(:tag))
65
65
  @html_attrs = options
@@ -4,14 +4,20 @@ require 'active_support/core_ext/object/blank'
4
4
  require 'active_support/core_ext/string/filters'
5
5
 
6
6
  module Bemer
7
- class EntityBuilder < Entity
7
+ class EntityBuilder < Entity # rubocop:disable Metrics/ClassLength
8
+ DATA_BEM_KEY = :'data-bem'
9
+
8
10
  def attrs
9
11
  attributes = Hash[super]
10
12
  attributes[:class] = cls if cls.present?
11
13
 
12
14
  return attributes unless bem?
13
15
 
14
- attributes.merge!(js)
16
+ data_bem = js
17
+
18
+ data_bem[DATA_BEM_KEY] = data_bem[DATA_BEM_KEY].to_json if data_bem.key?(DATA_BEM_KEY)
19
+
20
+ attributes.merge!(data_bem)
15
21
  end
16
22
 
17
23
  def attrs=(new_attrs, save = true)
@@ -39,9 +45,9 @@ module Bemer
39
45
  def cls
40
46
  return super unless bem?
41
47
 
42
- js_class = 'i-bem' if @js.present? && bem_class.present?
48
+ i_bem = 'i-bem' if need_data_bem? || need_mixed_data_bem?
43
49
 
44
- [bem_class, mods, mix, super, js_class].join(' ').squish
50
+ [bem_class, mods, mix, super, i_bem].flatten.reject(&:blank?).uniq.join(' ')
45
51
  end
46
52
 
47
53
  def cls=(new_cls, save = true)
@@ -55,11 +61,18 @@ module Bemer
55
61
  end
56
62
 
57
63
  def js
58
- return {} if @js.blank? || bem_class.blank?
64
+ need_data_bem = need_data_bem?
65
+ need_mixed_data_bem = need_mixed_data_bem?
59
66
 
60
- js_attrs = @js.instance_of?(TrueClass) ? {} : super
67
+ return {} unless need_data_bem || need_mixed_data_bem
61
68
 
62
- { 'data-bem': { name => js_attrs }.to_json }
69
+ if !need_data_bem && need_mixed_data_bem
70
+ mixed_data_bem
71
+ else
72
+ data_bem = @js.instance_of?(TrueClass) ? {} : super
73
+
74
+ { DATA_BEM_KEY => { name => data_bem }.merge!(mixed_data_bem[DATA_BEM_KEY]) }
75
+ end
63
76
  end
64
77
 
65
78
  def js=(new_js, save = true)
@@ -67,9 +80,15 @@ module Bemer
67
80
  end
68
81
 
69
82
  def mix=(new_mix, save = true)
70
- new_mix = MixinList.new(new_mix).to_a
83
+ new_mixes = Mixes.new(new_mix)
84
+ new_mix = new_mixes.to_a
71
85
 
72
- save ? @mix = new_mix : new_mix
86
+ if save
87
+ @mixins = new_mixes
88
+ @mix = new_mix
89
+ else
90
+ new_mix
91
+ end
73
92
  end
74
93
 
75
94
  def mods
@@ -93,8 +112,24 @@ module Bemer
93
112
  save ? @tag = new_tag : new_tag
94
113
  end
95
114
 
115
+ def need_data_bem?
116
+ bem? && @js.present? && bem_class.present?
117
+ end
118
+
119
+ def need_mixed_data_bem?
120
+ bem? && mixins.entities.any?(&:need_data_bem?)
121
+ end
122
+
96
123
  protected
97
124
 
125
+ def mixed_data_bem
126
+ mixins.entities.each_with_object(DATA_BEM_KEY => {}) do |entity, data_bem|
127
+ next unless entity.need_data_bem?
128
+
129
+ data_bem[DATA_BEM_KEY][entity.name] = entity.js[DATA_BEM_KEY][entity.name]
130
+ end
131
+ end
132
+
98
133
  def bem_via_option?
99
134
  !@bem.nil?
100
135
  end
data/lib/bemer/helpers.rb CHANGED
@@ -12,13 +12,16 @@ module Bemer
12
12
 
13
13
  # Использовать mix
14
14
  # Использовать mixs
15
+ # mixes
15
16
  # Использовать bemer_mix
16
17
  def bem_mix(*mix)
17
- Bemer::MixinList.new(mix).to_s
18
+ Bemer::Mixes.new(mix).to_s
18
19
  end
19
20
 
20
21
  # Использовать mods
21
22
  # Использовать mod
23
+ # modifier
24
+ # modifiers
22
25
  # Использовать bemer_mods
23
26
  def bem_mods(*block_and_element, mods)
24
27
  block, element = *block_and_element
@@ -51,5 +54,11 @@ module Bemer
51
54
  def component_partial_path(name)
52
55
  Bemer::PathResolver.new(self).resolve(name, true)
53
56
  end
57
+
58
+ def bem_attrs_for(block = '', element = nil, **options)
59
+ js = options[:js].nil? ? true : options.delete(:js)
60
+
61
+ Bemer::EntityBuilder.new(block, element, options.merge(bem: true, js: js)).attrs
62
+ end
54
63
  end
55
64
  end