tailmix 0.4.5 → 0.4.7

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: 6092dfded3153a41a28c7ca05e13fdbd52836c86b92576606aaafaabba030d12
4
- data.tar.gz: 2abf62eb8efb4a6fa6e7bc42da9a55e7e09610c9ad4a688af9030fb5a94c2d26
3
+ metadata.gz: 972f0dcd1667c6db95fbce07209fdf7ab3568b335fd0dab933977a641114dc6a
4
+ data.tar.gz: 3063e23f5422ec1fe5f20683263a6b7cfce4f9c054d393e520f962a0727d4992
5
5
  SHA512:
6
- metadata.gz: ba691f44a9ae33dab521b918f89858cbd2d4d08ae867330845ff403764a24ae63c87eafc1a20b8b73b5a1b9c1c4762673398f0b4c79427186bb42e96e4d48f40
7
- data.tar.gz: b7bb32552b876c9c59d3c2e82450e3200fe4fe3aa4267c4b6ef94f1151836bbfa10f74a10ac80f7044a0fe2fefd69cf8f8d0a0717d9749abe8dc8b1f99e2d42e
6
+ metadata.gz: fb3cfcfef0f342f12dc680a18e7a7d20b278b08699f28b09b473f8843747d147cd9a1ae56db112a86ce4c52881b609ecd6a9fe863fcdd43c9b63ff0ccc3f50cc
7
+ data.tar.gz: 75366e305721e6091324578ff4138f10b1d0ed70135d0094f901bb52f58580465f528731b498e23f2f61e26369dd4ad5d34425d28da81e26996c138c1d2872b9
data/README.md CHANGED
@@ -1,214 +1,304 @@
1
1
  # Tailmix
2
2
 
3
- **Tailmix** is a powerful, declarative, and interactive CSS class manager for building maintainable UI components in Ruby. It's designed to work seamlessly with utility-first CSS frameworks like **Tailwind CSS**, allowing you to co-locate your style logic with your component's code—in a clean, structured, and highly reusable way.
3
+ **Tailmix** is a powerful, declarative engine for managing HTML attributes in Ruby UI components. It allows you to co-locate all presentational logic—including CSS classes, data attributes, and ARIA roles—directly within your component's code, creating truly self-contained and maintainable components.
4
4
 
5
- [![Gem Version](https://badge.fury.io/rb/tailmix.svg)](https://badge.fury.io/rb/tailmix)
6
- [![Build Status](https://github.com/alexander-s-f/tailmix/actions/workflows/main.yml/badge.svg)](https://github.com/alexander-s-f/tailmix/actions/workflows/main.yml)
5
+ [](https://badge.fury.io/rb/tailmix)
6
+ [](https://github.com/alexander-s-f/tailmix/actions/workflows/main.yml)
7
7
 
8
8
  Inspired by modern frontend tools like CVA (Class Variance Authority), Tailmix brings a robust styling engine to your server-side components (built with Arbre, ViewComponent, Phlex, etc.).
9
9
 
10
- ## Philosophy
10
+ ## Key Features
11
11
 
12
- * **Co-location & Isolation:** Define all style variants for a component directly within its class. No more hunting for styles in separate files. Each component is fully self-contained.
13
- * **Declarative First:** A beautiful DSL to declaratively describe your component's appearance based on variants like state, size, etc.
14
- * **Imperative Power:** A rich runtime API to dynamically add, remove, or toggle classes, perfect for server-side updates via Hotwire/Turbo.
15
- * **Framework-Agnostic:** Written in pure Ruby with zero dependencies, ready to be used in any project.
12
+ * **Declarative DSL:** Describe your component's styles with an elegant and intuitive API.
13
+ * **Variants & Compound Variants:** Easily manage different component states (`size`, `color`, etc.) and their combinations.
14
+ * **Stimulus Bridge:** Seamlessly integrate with StimulusJS to create interactive components.
15
+ * **"Hot" UI Updates:** Enable optimistic UI updates with `action` and `action_payload` in tandem with Hotwire/Turbo.
16
+ * **Component Inheritance:** Create base components and extend them to avoid code duplication.
17
+ * **Developer Tools:** Get built-in documentation and code generators right in your console.
18
+ * **Zero Dependencies:** Pure Ruby, ready to work in any project.
16
19
 
17
- ## Installation
20
+ -----
18
21
 
19
- Add the gem to your Gemfile:
22
+ ## Quick Links
23
+
24
+ * **[Full Documentation →](/docs)**
25
+ * **[DSL Reference](/docs/02_dsl_reference.md)**
26
+ * **[Cookbook (Recipes)](/docs/05_cookbook.md)**
20
27
 
21
- ```ruby
22
- gem 'tailmix'
23
- ````
24
28
 
25
- Or install it from the command line:
29
+ -----
30
+
31
+ ## Installation
32
+
33
+ Add the gem to your Gemfile:
26
34
 
27
35
  ```bash
28
36
  bundle add tailmix
29
37
  ```
30
38
 
31
- Next, run the installer to set up the JavaScript assets:
39
+ Then, run the installer to set up the JavaScript assets (required for `action` and `Stimulus` integration):
32
40
 
33
41
  ```bash
34
42
  bin/rails g tailmix:install
35
43
  ```
36
44
 
37
- ## Core Concepts
45
+ -----
38
46
 
39
- You define your component's appearance using a simple `tailmix do ... end` DSL inside your class.
47
+ ## Usage
40
48
 
41
- - `element :name, "base classes"`: Defines a logical part of your component (e.g., `:wrapper`, `:panel`, `:icon`).
42
- - `dimension :name, default: :value`: Defines a variant or "dimension" (e.g., `size` or `color`).
43
- - `option :value, "classes"`: Defines the classes for a specific variant option.
44
- - `action :name, method: :add | :toggle | :remove`: Defines a named set of UI mutations that can be applied on the server (`.apply!`) or passed to the client (`action_payload`).
45
- - `stimulus`: A powerful nested DSL for declaratively describing Stimulus `data-*` attributes.
49
+ The core idea of Tailmix is to describe all variants of your component within a Ruby class.
46
50
 
47
- ## Usage Example
51
+ ### 1. Basic Example: The `Badge` Component
48
52
 
49
- Let's build a complex `ModalComponent` from scratch.
50
- #### 1. Define the Component (`app/components/modal_component.rb`)
53
+ Let's create a simple, flexible `Badge` that can have different colors.
51
54
 
52
- This is a plain Ruby class that contains all the style and behavior logic.
55
+ **Component Definition:**
53
56
 
54
57
  ```ruby
55
- class ModalComponent
58
+ # app/components/badge_component.rb
59
+ class BadgeComponent
56
60
  include Tailmix
57
- attr_reader :ui
61
+ attr_reader :ui, :text
62
+
63
+ def initialize(text, color: :gray)
64
+ @ui = tailmix(color: color)
65
+ @text = text
66
+ end
58
67
 
59
68
  tailmix do
60
- element :base, "fixed inset-0 z-50 flex items-center justify-center" do
61
- dimension :open, default: false do
62
- option true, "visible opacity-100"
63
- option false, "invisible opacity-0"
69
+ element :badge, "inline-flex items-center px-2.5 py-0.5 text-xs font-medium rounded-full" do
70
+ dimension :color, default: :gray do
71
+ variant :gray, "bg-gray-100 text-gray-800"
72
+ variant :success, "bg-green-100 text-green-800"
73
+ variant :danger, "bg-red-100 text-red-800"
64
74
  end
65
- stimulus.controller("modal")
66
75
  end
76
+ end
77
+ end
78
+ ```
67
79
 
68
- element :overlay, "fixed inset-0 bg-black/50 transition-opacity" do
69
- stimulus.context("modal").action(click: :close)
70
- end
80
+ **Usage in ERB:**
81
+ In ERB, use the `**` operator to pass the attributes.
71
82
 
72
- element :panel, "relative bg-white rounded-lg shadow-xl" do
73
- dimension :size, default: :md do
74
- option :sm, "w-full max-w-sm p-4"
75
- option :md, "w-full max-w-md p-6"
76
- end
77
- end
83
+ ```erb
84
+ <% badge = BadgeComponent.new("Active", color: :success) %>
78
85
 
79
- element :close_button, "absolute top-2 right-2 p-1 text-gray-400" do
80
- stimulus.context("modal").action(click: :close)
81
- end
86
+ <span <%= tag.attributes **badge.ui.badge %>>
87
+ <%= badge.text %>
88
+ </span>
89
+ ```
82
90
 
83
- element :confirm_button, "px-4 py-2 bg-blue-600 text-white rounded-md" do
84
- stimulus.controller("form-submission")
85
- .action(:click, :show_pending_state)
86
- .action_payload(:show_pending_state, as: :pending_data)
87
- end
88
-
89
- action :show_pending_state, method: :add do
90
- element :confirm_button do
91
- classes "is-loading"
92
- data pending: true
93
- end
94
- end
95
- end
91
+ **Usage in Arbre:**
92
+ Arbre was the primary inspiration for Tailmix. Integration is seamless and does not require the `**` operator.
96
93
 
97
- def initialize(open: false, size: :md)
98
- @ui = tailmix(open: open, size: size)
99
- end
94
+ ```ruby
95
+ # my_view.arb
96
+ badge = BadgeComponent.new("Active", color: :success)
97
+ ui = badge.ui
98
+
99
+ span ui.badge do
100
+ text_node badge.text
100
101
  end
101
102
  ```
102
103
 
103
- #### 2. Use in a View (Arbre, ERB, etc.)
104
+ ### 2\. Adding Interactivity with Stimulus
104
105
 
105
- Thanks to Tailmix's design, you can pass `ui` objects directly to many rendering helpers.
106
+ Tailmix allows you to declaratively define Stimulus controllers. Let's build a component to copy text to the clipboard.
106
107
 
107
- ##### Arbre
108
+ **Component Definition:**
108
109
 
109
- The API is seamless. The `ui` object behaves like an attributes hash automatically.
110
+ ```ruby
111
+ # app/components/clipboard_component.rb
112
+ class ClipboardComponent
113
+ include Tailmix
114
+ attr_reader :ui, :text_to_copy
110
115
 
111
- Ruby
116
+ def initialize(text_to_copy)
117
+ @ui = tailmix
118
+ @text_to_copy = text_to_copy
119
+ end
112
120
 
113
- ```ruby
114
- # app/views/components/my_modal.arb
115
- # 1. Instantiate the component with the desired variants
116
- modal = ModalComponent.new(open: true, size: :sm)
121
+ tailmix do
122
+ element :wrapper, "flex items-center space-x-2" do
123
+ stimulus.controller("clipboard") # data-controller="clipboard"
124
+ end
117
125
 
118
- # 2. Render by passing the ui objects directly to Arbre's tag helpers
119
- div modal.ui.base do
120
- div modal.ui.overlay
126
+ element :source, "p-2 border rounded-md bg-gray-50" do
127
+ stimulus.context("clipboard").target("source") # data-clipboard-target="source"
128
+ end
121
129
 
122
- div modal.ui.panel do
123
- # ... your content ...
124
- button modal.ui.confirm_button, "Confirm"
130
+ element :button, "px-3 py-2 text-sm font-medium text-white bg-blue-600 rounded-md" do
131
+ stimulus.context("clipboard").action(:click, :copy) # data-action="click->clipboard#copy"
132
+ end
125
133
  end
126
134
  end
127
135
  ```
128
136
 
129
- ##### ERB / Rails Tag Helpers
137
+ **Stimulus Controller:**
138
+ Generate a template with `puts ClipboardComponent.dev.stimulus.scaffold` and fill in the logic.
130
139
 
131
- In ERB, the idiomatic way to pass a hash-like object as attributes is with the double splat (`**`) operator.
140
+ ```javascript
141
+ // app/javascript/controllers/clipboard_controller.js
142
+ import { Controller } from "@hotwired/stimulus"
132
143
 
133
- Фрагмент кода
144
+ export default class extends Controller {
145
+ static targets = ["source"]
134
146
 
147
+ copy() {
148
+ navigator.clipboard.writeText(this.sourceTarget.textContent)
149
+ // Optionally: show a success notification
150
+ }
151
+ }
135
152
  ```
136
- <%# app/views/pages/home.html.erb %>
137
- <% modal = ModalComponent.new(open: true, size: :sm) %>
138
153
 
139
- <%= tag.div **modal.ui.base do %>
140
- <%= tag.div **modal.ui.overlay %>
154
+ Your component is now fully interactive, with its entire structure defined in a single Ruby file.
141
155
 
142
- <%= tag.div **modal.ui.panel do %>
143
- <%# ... your content ... %>
144
- <%= tag.button "Confirm", **modal.ui.confirm_button %>
145
- <% end %>
146
- <% end %>
147
- ```
156
+ -----
148
157
 
149
- #### 3. Bring it to Life with Stimulus
158
+ ## 3. Advanced Example: An Interactive Modal
150
159
 
151
- The `action_payload` helper makes it easy to connect server-side definitions with client-side behavior.
160
+ Now let's see the full power of Tailmix by building a common UI pattern: a fully interactive modal component. This example combines multiple elements, shared variants, Stimulus integration, and a client-side action for optimistic updates.
152
161
 
153
- JavaScript
162
+ Component Definition:
163
+ The `ModalComponent` definition is self-contained. It describes the structure, all possible states, and the interactive behavior of the modal.
154
164
 
155
- ```js
156
- // app/javascript/controllers/form_submission_controller.js
157
- import { Controller } from "@hotwired/stimulus"
158
- import Tailmix from "tailmix"
165
+ ```ruby
166
+ # app/components/modal_component.rb
167
+ class ModalComponent
168
+ include Tailmix
169
+ attr_reader :ui
159
170
 
160
- export default class extends Controller {
161
- static values = { pendingData: Object }
162
-
163
- showPendingState(event) {
164
- event.preventDefault()
165
-
166
- // Instantly apply UI changes from the payload
167
- Tailmix.run({
168
- config: this.pendingDataValue,
169
- controller: this
170
- });
171
-
172
- // ... then submit the form or send an AJAX request
173
- }
174
- }
175
- ```
171
+ tailmix do
172
+ # A container to hold the controller and its data
173
+ element :container do
174
+ stimulus.controller("modal")
175
+ .action_payload(:toggle, as: :toggle_data)
176
+ # dynamic values:
177
+ .value(:user_id, method: :get_current_user_id)
178
+ .value(:generated_at, call: -> { Time.now.iso8601 })
179
+ end
176
180
 
177
- ## Developer Tools
181
+ # The button that will trigger the modal
182
+ element :open_button, "inline-flex text-white bg-blue-600 rounded-lg px-5 py-2.5 cursor-pointer" do
183
+ stimulus.context("modal").action(:click, :toggle)
184
+ end
178
185
 
179
- Tailmix comes with built-in introspection tools to improve your development experience. Access them via the `.dev` namespace on your component class.
186
+ # The modal's backdrop and wrapper, controlled by the :open dimension
187
+ element :base, "flex items-center justify-center" do
188
+ dimension :open, default: false do
189
+ variant true, "fixed inset-0 z-50 visible opacity-100 transition-opacity"
190
+ variant false, "invisible opacity-0"
191
+ end
192
+ end
180
193
 
181
- #### Component Documentation
194
+ element :overlay, "fixed inset-0 bg-black/50" do
195
+ stimulus.context("modal").action(:click, :toggle)
196
+ end
182
197
 
183
- Get a cheat sheet of all available `dimensions` and `actions` right in your console.
198
+ # The main modal panel, with variants for both :open and :size
199
+ element :panel, "w-full relative bg-white rounded-lg shadow-xl" do
200
+ dimension :open, default: false do
201
+ variant true, "block"
202
+ variant false, "hidden"
203
+ end
204
+ dimension :size, default: :md do
205
+ variant :sm, "max-w-sm p-4"
206
+ variant :md, "max-w-md p-6"
207
+ end
208
+ stimulus.context("modal").target("panel")
209
+ end
184
210
 
185
- ```ruby
186
- puts ModalComponent.dev.docs
187
- ```
211
+ element :close_button, "absolute top-2 right-2 p-1 text-gray-500 rounded-full cursor-pointer" do
212
+ stimulus.context("modal").action(:click, :toggle)
213
+ end
188
214
 
189
- #### Stimulus Controller Generator
215
+ # The action that will be executed on the client-side
216
+ action :toggle, method: :toggle do
217
+ element :base do
218
+ classes "visible opacity-100"
219
+ classes "invisible opacity-0"
220
+ end
221
+ element :overlay do
222
+ classes "fixed inset-0 bg-black/50"
223
+ end
224
+ element :panel do
225
+ classes "block"
226
+ classes "hidden"
227
+ end
228
+ end
229
+ end
190
230
 
191
- Tailmix can analyze your component and scaffold a perfect boilerplate Stimulus controller with all targets, values, and action methods.
231
+ def initialize(size: :md, open: false)
232
+ @ui = tailmix(size: size, open: open)
233
+ end
192
234
 
193
- ```ruby
194
- puts ModalComponent.dev.stimulus.scaffold("modal")
235
+ def get_current_user_id
236
+ 123
237
+ end
238
+ end
195
239
  ```
196
240
 
197
- ## Configuration
241
+ **Stimulus Controller:**
242
+ This controller will handle the modal's open/close logic and use the `action_payload` to trigger the closing animation defined in Ruby.
243
+
244
+ ```javascript
245
+ // app/javascript/controllers/modal_controller.js
246
+ import { Controller } from "@hotwired/stimulus"
247
+ import Tailmix from "tailmix"
248
+
249
+ export default class extends Controller {
250
+ static values = { toggleData: Object }
251
+
252
+ toggle(event) {
253
+ // Prevent default browser behavior, like form submissions
254
+ if (event) event.preventDefault();
255
+
256
+ // Run the UI mutations defined in our Ruby :toggle action
257
+ Tailmix.run({
258
+ config: this.toggleDataValue,
259
+ controller: this
260
+ });
261
+ }
262
+ }
263
+ ```
198
264
 
199
- You can configure Tailmix by creating an initializer:
265
+ **View Usage (Arbre):**
266
+ The view code is clean and readable. We instantiate the component and render its elements. The action_payload is serialized to the container element, making it available to the Stimulus controller.
200
267
 
201
268
  ```ruby
202
- # config/initializers/tailmix.rb
203
- Tailmix.configure do |config|
204
- # The attribute used by the universal JS selector.
205
- config.element_selector_attribute = "data-tm-el"
269
+ # my_view.arb
270
+ modal = ModalComponent.new(size: :sm)
271
+ ui = modal.ui
272
+
273
+ div ui.container do
274
+ button "Open Modal", ui.open_button
275
+
276
+ div ui.base do
277
+ div ui.overlay
278
+ div ui.panel do
279
+ button "Close", ui.close_button
280
+ h3 "Payment Successful", ui.title
281
+
282
+ div ui.body do
283
+ "Your payment has been successfully submitted..."
284
+ end
285
+ end
286
+ end
206
287
  end
207
288
  ```
208
289
 
290
+ -----
291
+
292
+ ## Developer Tools
293
+
294
+ Use the `.dev` namespace to introspect your components right from the console.
295
+
296
+ * **`YourComponent.dev.docs`**: Displays full documentation for all variants and actions.
297
+ * **`YourComponent.dev.stimulus.scaffold`**: Generates a Stimulus controller template.
298
+
209
299
  ## Contributing
210
300
 
211
- Bug reports and pull requests are welcome on GitHub at [https://github.com/alexander-s-f/tailmix](https://github.com/alexander-s-f/tailmix).
301
+ Bug reports and pull requests are welcome on GitHub.
212
302
 
213
303
  ## License
214
304
 
@@ -1,12 +1,15 @@
1
- const SELECTOR_ATTRIBUTE = "data-tm-el";
2
-
3
1
  /**
4
- * find element [data-tm-el="..."]
2
+ * Finds an element by the new Tailmix selector convention.
3
+ * e.g., [data-tailmix-panel]
5
4
  * @param {HTMLElement} rootElement
6
- * @param {string} name
5
+ * @param {string} name - The logical name of the element (e.g., "panel").
7
6
  * @returns {HTMLElement|null}
8
7
  */
9
8
  export function findElement(rootElement, name) {
10
- const selector = `[${SELECTOR_ATTRIBUTE}="${name}"]`;
9
+ const selector = `[data-tailmix-${name}]`;
10
+
11
+ if (rootElement.matches(selector)) {
12
+ return rootElement;
13
+ }
11
14
  return rootElement.querySelector(selector);
12
15
  }
@@ -0,0 +1,120 @@
1
+ # Getting Started with Tailmix
2
+
3
+ Welcome to Tailmix! This guide will walk you through installing the gem, setting up your project, and creating your first component.
4
+
5
+ ## Philosophy
6
+
7
+ Tailmix is built on the idea of **co-location**. Instead of defining component styles in separate CSS, SCSS, or CSS-in-JS files, you define them directly within the Ruby class that represents your component. This creates self-contained, highly reusable, and easily maintainable UI components.
8
+
9
+ The core of Tailmix is a powerful and expressive **DSL (Domain-Specific Language)** that allows you to declaratively define how a component should look based on its properties or "variants".
10
+
11
+ ## Installation
12
+
13
+ Getting started with Tailmix involves two simple steps: adding the gem and installing the JavaScript bridge.
14
+
15
+ ### 1. Add the Gem
16
+
17
+ Add `tailmix` to your application's Gemfile:
18
+
19
+ ```bash
20
+ bundle add tailmix
21
+ ```
22
+
23
+ ### 2. Install JavaScript Assets
24
+
25
+ Run the installer to set up the necessary JavaScript files for the client-side bridge (used by actions).
26
+
27
+ ```bash
28
+ bin/rails g tailmix:install
29
+ ```
30
+
31
+ This command will add tailmix to your importmap.rb and ensure its JavaScript is available in your application.
32
+
33
+ ### Your First Component: A Badge
34
+ Let's create a simple BadgeComponent to see Tailmix in action.
35
+
36
+ #### 1. Define the Component Class
37
+
38
+ Create a new file in `app/components/badge_component.rb`:
39
+
40
+ ```ruby
41
+ # app/components/badge_component.rb
42
+ class BadgeComponent
43
+ include Tailmix
44
+ attr_reader :ui, :text
45
+
46
+ def initialize(text, color: :gray)
47
+ @ui = tailmix(color: color)
48
+ @text = text
49
+ end
50
+
51
+ tailmix do
52
+ element :badge, "inline-flex items-center px-2.5 py-0.5 text-xs font-medium rounded-full" do
53
+ dimension :color, default: :gray do
54
+ variant :gray, "bg-gray-100 text-gray-600"
55
+ variant :success, "bg-green-100 text-green-700"
56
+ variant :danger, "bg-red-100 text-red-700"
57
+ end
58
+ end
59
+ end
60
+ end
61
+ ```
62
+
63
+ #### 2. Use it in a View
64
+
65
+ Now, you can use this component in any ERB view:
66
+
67
+ ```html
68
+ <%# Create two instances of our badge with different variants %>
69
+ <% success_badge = BadgeComponent.new("Active", color: :success) %>
70
+ <% danger_badge = BadgeComponent.new("Inactive", color: :danger) %>
71
+
72
+ <span <%= tag.attributes **success_badge.ui.badge %>>
73
+ <%= success_badge.text %>
74
+ </span>
75
+
76
+ <span <%= tag.attributes **danger_badge.ui.badge %>>
77
+ <%= danger_badge.text %>
78
+ </span>
79
+ ```
80
+
81
+ #### View Usage .arb (Ruby Arbre)
82
+
83
+ ```ruby
84
+ # app/views/components/_badge.arb
85
+ success_badge = BadgeComponent.new("Active", color: :success)
86
+ danger_badge = BadgeComponent.new("Inactive", color: :danger)
87
+
88
+ span success_badge.ui.badge do
89
+ success_badge.text
90
+ end
91
+
92
+ span danger_badge.ui.badge do
93
+ danger_badge.text
94
+ end
95
+ ```
96
+
97
+ #### 3. The Resulting HTML
98
+
99
+ This will produce the following clean and semantic HTML:
100
+
101
+ ```html
102
+ <span class="inline-flex ... bg-green-100 text-green-700" data-tailmix-badge="color:success">
103
+ Active
104
+ </span>
105
+
106
+ <span class="inline-flex ... bg-red-100 text-red-700" data-tailmix-badge="color:danger">
107
+ Inactive
108
+ </span>
109
+ ```
110
+
111
+ Notice the `data-tailmix-badge` attribute, which serves as both a stable selector and a state indicator for your component.
112
+
113
+ ## Next Steps
114
+
115
+ - You've successfully created your first component! To learn more about the power of Tailmix, check out these documents:
116
+
117
+ - DSL Reference: For a deep dive into every available DSL method.
118
+
119
+ - Cookbook: For practical, real-world examples of common UI components.
120
+