element_component 0.11.0 → 0.12.0

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: c74ab0abe47013ad19304fcd1ad108855de1c85fdb4d7406e141d1797343d038
4
- data.tar.gz: 6b77e4cf5c1c73f90c251d45b6a83bde06aaf052452850bac7463f437c5c604e
3
+ metadata.gz: b327f66396580a4106a123f22a80cf6edb726a1d98b5b47dcea4f00d4df8649a
4
+ data.tar.gz: 2ba097718efa76c3418a62657eb9f2f897d67501a88f9942d8b002d7ac783acf
5
5
  SHA512:
6
- metadata.gz: dbf84809def7f1bd6b2ea85ebdafa81f217254bcba2505f123487063029d962cfd6c2379fe3dd308030cbb8ed97e800746fdbf2fe229888aaee53eeffa868d7c
7
- data.tar.gz: '039a7ccd1efb00032379fc3465a4f9c4b52feb7df276ad581a92d57f4970d9c471e65c8e37d545bfc81889e98793e4d8c97b8bd296adbdb1f97fe269d84ae36a'
6
+ metadata.gz: 83f7331b27128641ca774e75f5fd4e8ee4681402630f0091c31f27afe2397523e530e529ffb8481504555196a94ea530de820dbb278e03e9773eaf7a2bf55aa9
7
+ data.tar.gz: 988bada7149ec432984c71638e3cf4a53f309910093d10cebaf6a30ee13ff524697ebf19c7118c96625ff94575068eb5660c71902d992847943fa786b692a943
data/AGENTS.md CHANGED
@@ -12,6 +12,7 @@ lib/
12
12
  version.rb # VERSION constant
13
13
  element.rb # Core Element class
14
14
  components.rb # Component index, requires all components
15
+ aliases.rb # Namespace aliases and shortcuts
15
16
  components/
16
17
  alert.rb # Alert component
17
18
  alert/
@@ -76,6 +77,7 @@ spec/
76
77
  element_component_spec.rb # Version check
77
78
  lib/
78
79
  element_spec.rb # Element unit tests
80
+ aliases_spec.rb # Namespace aliases tests
79
81
  components/
80
82
  alert_spec.rb # Alert component tests
81
83
  badge_spec.rb # Badge component tests
@@ -99,18 +101,56 @@ examples/
99
101
  alert_example.rb # Complete Alert usage examples
100
102
  ```
101
103
 
104
+ ## Namespace Aliases
105
+
106
+ All components and the Element class can be accessed in multiple ways to reduce verbosity:
107
+
108
+ ### 1. Direct aliases (recommended)
109
+ ```ruby
110
+ ElementComponent::Card.new("content")
111
+ ElementComponent::Alert.new("message", variant: :success)
112
+ ElementComponent::E.new("div", "content")
113
+ ```
114
+
115
+ ### 2. Short module alias
116
+ ```ruby
117
+ EC::Card.new("content")
118
+ EC::E.new("span", "text")
119
+ ```
120
+
121
+ ### 3. Helper method for generic elements
122
+ ```ruby
123
+ ElementComponent.tag("div", "content", class: "container")
124
+ ElementComponent.tag("div") { |e| e.add_content("block") }
125
+ ```
126
+
127
+ ### 4. View shortcuts (include in views/helpers)
128
+ ```ruby
129
+ class MyView
130
+ include ElementComponent::Shortcuts
131
+
132
+ def render
133
+ Card.new("content")
134
+ E.new("span", "text")
135
+ tag("div", "content")
136
+ end
137
+ end
138
+ ```
139
+
140
+ **All 48 components are available** via all four access patterns above.
141
+
102
142
  ## Core Classes
103
143
 
104
- ### `ElementComponent::Element`
144
+ ### `ElementComponent::Element` (alias: `ElementComponent::E`)
105
145
  - **Attributes**: `element` (tag name), `attributes` (Hash), `contents` (Array), `html` (rendered output)
106
- - **Constructor**: `Element.new(tag_name, closing_tag: true, **attributes)`
146
+ - **Constructor**: `Element.new(tag_name, content = nil, closing_tag: true, **attributes, &block)`
107
147
  - **Content methods**: `add_content`, `add_content!`, `add_content(&block)` — `content` can be a single value or an Array of values
108
148
  - **Attribute methods**: `add_attribute`, `add_attribute!`, `remove_attribute`, `remove_attribute_value`
109
149
  - **Render**: `render` (with hooks: `before_render`, `after_render`, `around_render`)
110
150
 
111
151
  ### Pre-built Components
112
152
 
113
- Components live under `ElementComponent::Components`. Each component folder contains the main class and its sub-components in separate files.
153
+ Components live under `ElementComponent::Components` (alias: `EC`). Direct aliases are also available under `ElementComponent::`.
114
154
 
115
155
  | Component | Class | Tag | Key Options |
116
156
  |---|---|---|---|
@@ -132,7 +172,8 @@ Components live under `ElementComponent::Components`. Each component folder cont
132
172
  | Spinner | `Spinner` | `<div>` | `type` (border/grow), `variant` |
133
173
  | Table | `Table` | `<table>` | `striped`, `bordered`, `hover`, `small`, `variant` |
134
174
 
135
- **Alert constructor**: `Alert.new(variant: :primary, dismissible: false, **attributes, &block)`
175
+ **Alert constructor**: `Alert.new(content = nil, variant: :primary, dismissible: false, **attributes, &block)`
176
+ - `content`: optional content string or array, added before block content
136
177
  - `variant`: one of `:primary`, `:secondary`, `:success`, `:danger`, `:warning`, `:info`, `:light`, `:dark`
137
178
  - `dismissible`: adds `.alert-dismissible` class and appends a `CloseButton`
138
179
  - `&block`: block with element parameter for adding content inside the element
@@ -140,18 +181,61 @@ Components live under `ElementComponent::Components`. Each component folder cont
140
181
  **Component guidelines**:
141
182
  - Always use `add_attribute()` instead of manipulating the `attributes` hash directly
142
183
  - Each class in its own file under a component-named folder
143
- - Call `super("tag_name", closing_tag: ..., &block)` first, then chain `add_attribute` calls
144
- - `block.call(self)` lives in `Element#initialize` passes element to block via block parameter
184
+ - **Constructor pattern**: `def initialize(content = nil, **keyword_args, **attributes, &block)`
185
+ - Call `super("tag_name", &block)` first, then chain `add_attribute` calls, then `add_content(content) if content`
186
+ - Content from the `content` argument is added **before** block content
145
187
  - Pass user attributes last via `add_attribute(attributes)`
146
188
 
147
- ### Sub-component example pattern:
189
+ ### Component constructor pattern:
148
190
 
149
191
  ```ruby
150
192
  class AlertHeading < Element
151
- def initialize(**attributes, &block)
152
- super("h4", &block)
193
+ def initialize(content = nil, **attributes)
194
+ super("h4")
153
195
  add_attribute(class: "alert-heading")
154
- add_attribute(attributes)
196
+ add_attribute(attributes) unless attributes.empty?
197
+ add_content(content) if content
198
+ end
199
+ end
200
+ ```
201
+
202
+ ### Components with internal content (e.g., Alert, ModalHeader):
203
+
204
+ ```ruby
205
+ class Alert < Element
206
+ def initialize(content = nil, variant: :primary, dismissible: false, **attributes, &block)
207
+ super("div", &block)
208
+
209
+ add_attribute(class: "alert")
210
+ add_attribute(class: "alert-\#{variant}")
211
+ add_attribute(class: "alert-dismissible") if dismissible
212
+ add_attribute(role: "alert")
213
+
214
+ add_attribute(attributes) unless attributes.empty?
215
+ add_content(content) if content # user content first
216
+ add_content(AlertCloseButton.new) if dismissible # internal content after
217
+ end
218
+ end
219
+ ```
220
+
221
+ ### Components with conditional tag names (e.g., Button, ListGroupItem):
222
+
223
+ ```ruby
224
+ class Button < Element
225
+ def initialize(content = nil, variant: :primary, outline: false, size: nil, href: nil, **attributes, &block)
226
+ if href
227
+ super("a", &block)
228
+ add_attribute(href: href)
229
+ else
230
+ super("button", &block)
231
+ add_attribute(type: "button")
232
+ end
233
+
234
+ add_attribute(class: "btn")
235
+ add_attribute(class: outline ? "btn-outline-\#{variant}" : "btn-\#{variant}")
236
+ add_attribute(class: "btn-\#{size}") if size
237
+ add_attribute(attributes) unless attributes.empty?
238
+ add_content(content) if content
155
239
  end
156
240
  end
157
241
  ```
@@ -184,6 +268,7 @@ ruby examples/alert_example.rb # Run Alert examples
184
268
  - Test render output as raw HTML strings
185
269
  - Test attribute hashes directly
186
270
  - Follow existing describe/context/it structure
271
+ - Test new aliases in `spec/lib/aliases_spec.rb`
187
272
 
188
273
  ## Development Workflow
189
274
 
@@ -202,6 +287,13 @@ ruby examples/alert_example.rb # Run Alert examples
202
287
  - Hooks (`before_render`, `after_render`, `around_render`) are optional, detected via `respond_to?`
203
288
  - Self-closing tags controlled by `closing_tag:` parameter
204
289
  - Component classes use `add_attribute()` instead of direct hash manipulation
290
+ - `content` as first positional argument in all constructors (optional, default `nil`)
291
+ - Content argument is added before block content when both are provided
292
+ - All 48 components are aliased directly under `ElementComponent::` for convenience
293
+ - `ElementComponent::E` is an alias for `ElementComponent::Element`
294
+ - `ElementComponent::EC` is an alias for `ElementComponent::Components`
295
+ - `ElementComponent.tag()` is a helper method for creating generic elements
296
+ - `ElementComponent::Shortcuts` module provides instance methods for use in views/helpers
205
297
 
206
298
  ## Roadmap Features (from README)
207
299
  - Caching support
@@ -0,0 +1,116 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ElementComponent
4
+ E = Element
5
+
6
+ def self.tag(name, content = nil, **attributes, &)
7
+ Element.new(name, content, **attributes, &)
8
+ end
9
+
10
+ EC = Components
11
+
12
+ Alert = Components::Alert
13
+ Badge = Components::Badge
14
+ Breadcrumb = Components::Breadcrumb
15
+ Button = Components::Button
16
+ ButtonGroup = Components::ButtonGroup
17
+ Card = Components::Card
18
+ Carousel = Components::Carousel
19
+ CloseButton = Components::CloseButton
20
+ Dropdown = Components::Dropdown
21
+ ListGroup = Components::ListGroup
22
+ Modal = Components::Modal
23
+ Nav = Components::Nav
24
+ Navbar = Components::Navbar
25
+ Pagination = Components::Pagination
26
+ Progress = Components::Progress
27
+ Spinner = Components::Spinner
28
+ Table = Components::Table
29
+
30
+ AlertHeading = Components::AlertHeading
31
+ AlertLink = Components::AlertLink
32
+ AlertCloseButton = Components::AlertCloseButton
33
+ BreadcrumbItem = Components::BreadcrumbItem
34
+ CardHeader = Components::CardHeader
35
+ CardBody = Components::CardBody
36
+ CardFooter = Components::CardFooter
37
+ CardTitle = Components::CardTitle
38
+ CardText = Components::CardText
39
+ CardImage = Components::CardImage
40
+ CarouselItem = Components::CarouselItem
41
+ CarouselCaption = Components::CarouselCaption
42
+ DropdownMenu = Components::DropdownMenu
43
+ DropdownItem = Components::DropdownItem
44
+ DropdownDivider = Components::DropdownDivider
45
+ DropdownHeader = Components::DropdownHeader
46
+ ListGroupItem = Components::ListGroupItem
47
+ ModalDialog = Components::ModalDialog
48
+ ModalContent = Components::ModalContent
49
+ ModalHeader = Components::ModalHeader
50
+ ModalTitle = Components::ModalTitle
51
+ ModalBody = Components::ModalBody
52
+ ModalFooter = Components::ModalFooter
53
+ NavItem = Components::NavItem
54
+ NavLink = Components::NavLink
55
+ NavbarBrand = Components::NavbarBrand
56
+ NavbarToggler = Components::NavbarToggler
57
+ NavbarCollapse = Components::NavbarCollapse
58
+ NavbarNav = Components::NavbarNav
59
+ PageItem = Components::PageItem
60
+ ProgressBar = Components::ProgressBar
61
+
62
+ # rubocop:disable Naming/MethodName
63
+ module Shortcuts
64
+ def Card(...) = ElementComponent::Card.new(...)
65
+ def Alert(...) = ElementComponent::Alert.new(...)
66
+ def Badge(...) = ElementComponent::Badge.new(...)
67
+ def Button(...) = ElementComponent::Button.new(...)
68
+ def ButtonGroup(...) = ElementComponent::ButtonGroup.new(...)
69
+ def Breadcrumb(...) = ElementComponent::Breadcrumb.new(...)
70
+ def Carousel(...) = ElementComponent::Carousel.new(...)
71
+ def CloseButton(...) = ElementComponent::CloseButton.new(...)
72
+ def Dropdown(...) = ElementComponent::Dropdown.new(...)
73
+ def ListGroup(...) = ElementComponent::ListGroup.new(...)
74
+ def Modal(...) = ElementComponent::Modal.new(...)
75
+ def Nav(...) = ElementComponent::Nav.new(...)
76
+ def Navbar(...) = ElementComponent::Navbar.new(...)
77
+ def Pagination(...) = ElementComponent::Pagination.new(...)
78
+ def Progress(...) = ElementComponent::Progress.new(...)
79
+ def Spinner(...) = ElementComponent::Spinner.new(...)
80
+ def Table(...) = ElementComponent::Table.new(...)
81
+ def AlertHeading(...) = ElementComponent::AlertHeading.new(...)
82
+ def AlertLink(...) = ElementComponent::AlertLink.new(...)
83
+ def AlertCloseButton(...) = ElementComponent::AlertCloseButton.new(...)
84
+ def BreadcrumbItem(...) = ElementComponent::BreadcrumbItem.new(...)
85
+ def CardHeader(...) = ElementComponent::CardHeader.new(...)
86
+ def CardBody(...) = ElementComponent::CardBody.new(...)
87
+ def CardFooter(...) = ElementComponent::CardFooter.new(...)
88
+ def CardTitle(...) = ElementComponent::CardTitle.new(...)
89
+ def CardText(...) = ElementComponent::CardText.new(...)
90
+ def CardImage(...) = ElementComponent::CardImage.new(...)
91
+ def CarouselItem(...) = ElementComponent::CarouselItem.new(...)
92
+ def CarouselCaption(...) = ElementComponent::CarouselCaption.new(...)
93
+ def DropdownMenu(...) = ElementComponent::DropdownMenu.new(...)
94
+ def DropdownItem(...) = ElementComponent::DropdownItem.new(...)
95
+ def DropdownDivider(...) = ElementComponent::DropdownDivider.new(...)
96
+ def DropdownHeader(...) = ElementComponent::DropdownHeader.new(...)
97
+ def ListGroupItem(...) = ElementComponent::ListGroupItem.new(...)
98
+ def ModalDialog(...) = ElementComponent::ModalDialog.new(...)
99
+ def ModalContent(...) = ElementComponent::ModalContent.new(...)
100
+ def ModalHeader(...) = ElementComponent::ModalHeader.new(...)
101
+ def ModalTitle(...) = ElementComponent::ModalTitle.new(...)
102
+ def ModalBody(...) = ElementComponent::ModalBody.new(...)
103
+ def ModalFooter(...) = ElementComponent::ModalFooter.new(...)
104
+ def NavItem(...) = ElementComponent::NavItem.new(...)
105
+ def NavLink(...) = ElementComponent::NavLink.new(...)
106
+ def NavbarBrand(...) = ElementComponent::NavbarBrand.new(...)
107
+ def NavbarToggler(...) = ElementComponent::NavbarToggler.new(...)
108
+ def NavbarCollapse(...) = ElementComponent::NavbarCollapse.new(...)
109
+ def NavbarNav(...) = ElementComponent::NavbarNav.new(...)
110
+ def PageItem(...) = ElementComponent::PageItem.new(...)
111
+ def ProgressBar(...) = ElementComponent::ProgressBar.new(...)
112
+ def E(...) = ElementComponent::E.new(...)
113
+ def tag(...) = ElementComponent.tag(...)
114
+ end
115
+ # rubocop:enable Naming/MethodName
116
+ end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module ElementComponent
4
- VERSION = "0.11.0"
4
+ VERSION = "0.12.0"
5
5
  end
@@ -3,6 +3,7 @@
3
3
  require_relative "element_component/version"
4
4
  require_relative "element_component/element"
5
5
  require_relative "element_component/components"
6
+ require_relative "element_component/aliases"
6
7
 
7
8
  module ElementComponent
8
9
  class Error < StandardError; end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: element_component
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.11.0
4
+ version: 0.12.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - João Paulo Correia
@@ -40,6 +40,7 @@ files:
40
40
  - examples/spinner_example.rb
41
41
  - examples/table_example.rb
42
42
  - lib/element_component.rb
43
+ - lib/element_component/aliases.rb
43
44
  - lib/element_component/components.rb
44
45
  - lib/element_component/components/alert.rb
45
46
  - lib/element_component/components/alert/close_button.rb