plutonium 0.23.4 → 0.24.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 +4 -4
- data/app/assets/plutonium.css +2 -2
- data/config/initializers/rabl.rb +17 -0
- data/config/initializers/sqlite_json_alias.rb +1 -1
- data/docs/.vitepress/config.ts +60 -19
- data/docs/guide/cursor-rules.md +75 -0
- data/docs/guide/deep-dive/authorization.md +189 -0
- data/docs/guide/{getting-started → deep-dive}/resources.md +137 -0
- data/docs/guide/getting-started/{installation.md → 01-installation.md} +0 -105
- data/docs/guide/index.md +28 -0
- data/docs/guide/introduction/02-core-concepts.md +440 -0
- data/docs/guide/tutorial/01-project-setup.md +75 -0
- data/docs/guide/tutorial/02-creating-a-feature-package.md +45 -0
- data/docs/guide/tutorial/03-defining-resources.md +90 -0
- data/docs/guide/tutorial/04-creating-a-portal.md +101 -0
- data/docs/guide/tutorial/05-customizing-the-ui.md +128 -0
- data/docs/guide/tutorial/06-adding-custom-actions.md +101 -0
- data/docs/guide/tutorial/07-implementing-authorization.md +90 -0
- data/docs/index.md +24 -31
- data/docs/modules/action.md +190 -0
- data/docs/modules/authentication.md +236 -0
- data/docs/modules/configuration.md +599 -0
- data/docs/modules/controller.md +398 -0
- data/docs/modules/core.md +316 -0
- data/docs/modules/definition.md +876 -0
- data/docs/modules/display.md +759 -0
- data/docs/modules/form.md +465 -0
- data/docs/modules/generator.md +288 -0
- data/docs/modules/index.md +167 -0
- data/docs/modules/interaction.md +470 -0
- data/docs/modules/package.md +151 -0
- data/docs/modules/policy.md +176 -0
- data/docs/modules/portal.md +710 -0
- data/docs/modules/query.md +287 -0
- data/docs/modules/resource_record.md +618 -0
- data/docs/modules/routing.md +641 -0
- data/docs/modules/table.md +293 -0
- data/docs/modules/ui.md +631 -0
- data/docs/public/plutonium.mdc +667 -0
- data/lib/generators/pu/core/assets/assets_generator.rb +0 -5
- data/lib/plutonium/definition/nested_inputs.rb +0 -8
- data/lib/plutonium/resource/controller.rb +1 -1
- data/lib/plutonium/ui/display/resource.rb +7 -2
- data/lib/plutonium/ui/table/resource.rb +8 -3
- data/lib/plutonium/version.rb +1 -1
- metadata +36 -9
- data/docs/guide/getting-started/authorization.md +0 -296
- data/docs/guide/getting-started/core-concepts.md +0 -432
- data/docs/guide/getting-started/index.md +0 -21
- data/docs/guide/tutorial.md +0 -401
- /data/docs/guide/{what-is-plutonium.md → introduction/01-what-is-plutonium.md} +0 -0
@@ -0,0 +1,465 @@
|
|
1
|
+
---
|
2
|
+
title: Form Module
|
3
|
+
---
|
4
|
+
|
5
|
+
# Form Module
|
6
|
+
|
7
|
+
The Form module is Plutonium's comprehensive system for building powerful, modern, and secure forms. It extends the `Phlexi::Form` library to provide a suite of enhanced input components, automatic field inference, secure-by-default associations, and seamless integration with your resources. This module is designed to make creating rich, accessible, and interactive forms a breeze.
|
8
|
+
|
9
|
+
::: tip
|
10
|
+
The Form module is located in `lib/plutonium/ui/form/`.
|
11
|
+
:::
|
12
|
+
|
13
|
+
## Key Features
|
14
|
+
|
15
|
+
- **Rich Input Components**: Out-of-the-box support for markdown editors, date pickers, file uploads with previews, and international phone inputs.
|
16
|
+
- **Secure by Default**: All associations use Signed Global IDs (SGIDs) to prevent parameter tampering, with automatic authorization checks.
|
17
|
+
- **Intelligent Type Inference**: Automatically selects the best input component based on Active Record column types, saving you from boilerplate.
|
18
|
+
- **Deep Resource Integration**: Generate forms automatically from your resource definitions, including support for conditional fields.
|
19
|
+
- **Modern Frontend**: A complete theme system built with Tailwind CSS, Stimulus for interactivity, and first-class dark mode support.
|
20
|
+
- **Complex Form Structures**: Easily manage associations with nested forms supporting dynamic "add" and "remove" functionality.
|
21
|
+
|
22
|
+
## Core Form Classes
|
23
|
+
|
24
|
+
Plutonium provides several base form classes, each tailored for a specific purpose.
|
25
|
+
|
26
|
+
### `Form::Base`
|
27
|
+
|
28
|
+
This is the foundation for all forms in Plutonium. It extends `Phlexi::Form::Base` and includes the core form builder with all the custom input components. You can inherit from this class to create custom, one-off forms.
|
29
|
+
|
30
|
+
::: details Builder Implementation
|
31
|
+
The `Builder` class within `Form::Base` is where all the custom input tag methods are defined. It aliases standard Rails form helpers like `belongs_to_tag` to Plutonium's secure and enhanced versions.
|
32
|
+
|
33
|
+
```ruby
|
34
|
+
class Plutonium::UI::Form::Base < Phlexi::Form::Base
|
35
|
+
# ...
|
36
|
+
class Builder < Builder
|
37
|
+
include Plutonium::UI::Form::Options::InferredTypes
|
38
|
+
|
39
|
+
# Enhanced input components
|
40
|
+
def easymde_tag(**); end
|
41
|
+
alias_method :markdown_tag, :easymde_tag
|
42
|
+
|
43
|
+
def flatpickr_tag(**); end
|
44
|
+
def int_tel_input_tag(**); end
|
45
|
+
alias_method :phone_tag, :int_tel_input_tag
|
46
|
+
|
47
|
+
def uppy_tag(**); end
|
48
|
+
alias_method :file_tag, :uppy_tag
|
49
|
+
alias_method :attachment_tag, :uppy_tag
|
50
|
+
|
51
|
+
def slim_select_tag(**); end
|
52
|
+
def secure_association_tag(**); end
|
53
|
+
def secure_polymorphic_association_tag(**); end
|
54
|
+
|
55
|
+
# Override default association methods
|
56
|
+
alias_method :belongs_to_tag, :secure_association_tag
|
57
|
+
alias_method :has_many_tag, :secure_association_tag
|
58
|
+
alias_method :has_one_tag, :secure_association_tag
|
59
|
+
alias_method :polymorphic_belongs_to_tag, :secure_polymorphic_association_tag
|
60
|
+
end
|
61
|
+
end
|
62
|
+
```
|
63
|
+
:::
|
64
|
+
|
65
|
+
### `Form::Resource`
|
66
|
+
|
67
|
+
This is a specialized form that intelligently renders inputs based on a resource definition. It's the primary way you'll create `new` and `edit` forms for your models. It automatically handles field rendering, nested resources, and conditional logic defined in your resource class.
|
68
|
+
|
69
|
+
```ruby
|
70
|
+
class Plutonium::UI::Form::Resource < Base
|
71
|
+
include Plutonium::UI::Form::Concerns::RendersNestedResourceFields
|
72
|
+
|
73
|
+
def initialize(object, resource_fields:, resource_definition:, **options)
|
74
|
+
# ...
|
75
|
+
end
|
76
|
+
|
77
|
+
def form_template
|
78
|
+
render_fields # Renders inputs from resource_definition
|
79
|
+
render_actions # Renders submit/cancel buttons
|
80
|
+
end
|
81
|
+
end
|
82
|
+
```
|
83
|
+
|
84
|
+
### `Form::Query`
|
85
|
+
|
86
|
+
This form is built for search and filtering. It integrates with Plutonium's Query Objects to create search inputs, dynamic filter controls, and hidden fields for sorting and pagination, all submitted via GET requests to preserve filterable URLs.
|
87
|
+
|
88
|
+
```ruby
|
89
|
+
class Plutonium::UI::Form::Query < Base
|
90
|
+
def initialize(object, query_object:, page_size:, **options)
|
91
|
+
# ... configured as a GET form with Turbo integration
|
92
|
+
end
|
93
|
+
|
94
|
+
def form_template
|
95
|
+
render_search_fields
|
96
|
+
render_filter_fields
|
97
|
+
render_sort_fields
|
98
|
+
render_scope_fields
|
99
|
+
end
|
100
|
+
end
|
101
|
+
```
|
102
|
+
|
103
|
+
### `Form::Interaction`
|
104
|
+
|
105
|
+
This specialized form is designed for handling user interactions and actions. It automatically configures itself based on an interaction object, setting up the appropriate fields and form behavior for interactive actions.
|
106
|
+
|
107
|
+
```ruby
|
108
|
+
class Plutonium::UI::Form::Interaction < Resource
|
109
|
+
def initialize(interaction, **options)
|
110
|
+
# Automatically configures fields from interaction attributes
|
111
|
+
options[:resource_fields] = interaction.attribute_names.map(&:to_sym) - %i[resource resources]
|
112
|
+
options[:resource_definition] = interaction
|
113
|
+
# ...
|
114
|
+
end
|
115
|
+
|
116
|
+
# Form posts to the same page for interaction handling
|
117
|
+
def form_action
|
118
|
+
nil
|
119
|
+
end
|
120
|
+
end
|
121
|
+
```
|
122
|
+
|
123
|
+
## Enhanced Input Components
|
124
|
+
|
125
|
+
Plutonium replaces standard form inputs with enhanced versions that provide a modern user experience.
|
126
|
+
|
127
|
+
### Markdown Editor (Easymde)
|
128
|
+
|
129
|
+
For rich text content, Plutonium integrates a client-side markdown editor based on [EasyMDE](https://github.com/Ionaru/easy-markdown-editor). It's automatically used for `rich_text` fields (like ActionText) and provides a live preview.
|
130
|
+
|
131
|
+
::: code-group
|
132
|
+
```ruby [Automatic Usage]
|
133
|
+
# Automatically used for ActionText rich_text fields
|
134
|
+
render field(:content).easymde_tag
|
135
|
+
|
136
|
+
# Or explicitly with an alias
|
137
|
+
render field(:description).markdown_tag
|
138
|
+
```
|
139
|
+
:::
|
140
|
+
|
141
|
+
::: details Component Internals
|
142
|
+
The component renders a `textarea` with a `data-controller="easymde"` attribute. It also includes logic to correctly handle ActionText objects by calling `to_plain_text` on the value.
|
143
|
+
|
144
|
+
```ruby
|
145
|
+
class Plutonium::UI::Form::Components::Easymde < Phlexi::Form::Components::Base
|
146
|
+
def view_template
|
147
|
+
textarea(**attributes, data_controller: "easymde") do
|
148
|
+
normalize_value(field.value)
|
149
|
+
end
|
150
|
+
end
|
151
|
+
# ...
|
152
|
+
end
|
153
|
+
```
|
154
|
+
:::
|
155
|
+
|
156
|
+
### Date/Time Picker (Flatpickr)
|
157
|
+
|
158
|
+
A beautiful and lightweight date/time picker from [Flatpickr](https://flatpickr.js.org/). It's automatically enabled for `date`, `time`, and `datetime` fields.
|
159
|
+
|
160
|
+
::: code-group
|
161
|
+
```ruby [Automatic Usage]
|
162
|
+
# Automatically used based on field type
|
163
|
+
render field(:published_at).flatpickr_tag # datetime field
|
164
|
+
render field(:event_date).flatpickr_tag # date field
|
165
|
+
render field(:meeting_time).flatpickr_tag # time field
|
166
|
+
```
|
167
|
+
:::
|
168
|
+
|
169
|
+
::: details Component Internals
|
170
|
+
The component simply adds a `data-controller="flatpickr"` attribute to a standard input. The corresponding Stimulus controller then inspects the input's `type` attribute (`date`, `time`, or `datetime-local`) to initialize Flatpickr with the correct options (e.g., with or without the time picker).
|
171
|
+
|
172
|
+
```ruby
|
173
|
+
class Plutonium::UI::Form::Components::Flatpickr < Phlexi::Form::Components::Input
|
174
|
+
private
|
175
|
+
|
176
|
+
def build_input_attributes
|
177
|
+
super
|
178
|
+
attributes[:data_controller] = tokens(attributes[:data_controller], :flatpickr)
|
179
|
+
end
|
180
|
+
end
|
181
|
+
```
|
182
|
+
:::
|
183
|
+
|
184
|
+
### International Phone Input
|
185
|
+
|
186
|
+
For phone numbers, a user-friendly input with a country-code dropdown is provided by [intl-tel-input](https://github.com/jackocnr/intl-tel-input).
|
187
|
+
|
188
|
+
::: code-group
|
189
|
+
```ruby [Usage]
|
190
|
+
# Automatically used for fields of type :tel
|
191
|
+
render field(:phone).int_tel_input_tag
|
192
|
+
|
193
|
+
# Or using its alias
|
194
|
+
render field(:mobile).phone_tag
|
195
|
+
```
|
196
|
+
:::
|
197
|
+
|
198
|
+
::: details Component Internals
|
199
|
+
This component wraps the input in a `div` with a `data-controller="intl-tel-input"` and adds a `data_intl_tel_input_target` to the input itself, allowing the Stimulus controller to initialize the library.
|
200
|
+
|
201
|
+
```ruby
|
202
|
+
class Plutonium::UI::Form::Components::IntlTelInput < Phlexi::Form::Components::Input
|
203
|
+
def view_template
|
204
|
+
div(data_controller: "intl-tel-input") do
|
205
|
+
super # Renders the input with proper data targets
|
206
|
+
end
|
207
|
+
end
|
208
|
+
|
209
|
+
private
|
210
|
+
|
211
|
+
def build_input_attributes
|
212
|
+
super
|
213
|
+
attributes[:data_intl_tel_input_target] = tokens(attributes[:data_intl_tel_input_target], :input)
|
214
|
+
end
|
215
|
+
end
|
216
|
+
```
|
217
|
+
:::
|
218
|
+
|
219
|
+
### File Upload (Uppy)
|
220
|
+
|
221
|
+
File uploads are handled by [Uppy](https://uppy.io/), a sleek, modern uploader. It supports drag & drop, progress indicators, direct-to-cloud uploads, and interactive previews for existing attachments.
|
222
|
+
|
223
|
+
::: code-group
|
224
|
+
```ruby [Basic Usage]
|
225
|
+
# Automatically used for file and Active Storage attachments
|
226
|
+
render field(:avatar).uppy_tag
|
227
|
+
render field(:documents).file_tag # alias
|
228
|
+
render field(:gallery).attachment_tag # alias
|
229
|
+
```
|
230
|
+
|
231
|
+
```ruby [With Options]
|
232
|
+
render field(:documents).uppy_tag(
|
233
|
+
multiple: true,
|
234
|
+
direct_upload: true, # For S3, etc.
|
235
|
+
max_file_size: 10.megabytes,
|
236
|
+
allowed_file_types: ['.pdf', '.doc']
|
237
|
+
)
|
238
|
+
```
|
239
|
+
:::
|
240
|
+
|
241
|
+
::: details Component Internals
|
242
|
+
The Uppy component is quite sophisticated. It renders an interactive preview grid for existing attachments (each with its own `attachment-preview` Stimulus controller for deletion) and a file input managed by an `attachment-input` Stimulus controller that initializes Uppy.
|
243
|
+
|
244
|
+
```ruby
|
245
|
+
class Plutonium::UI::Form::Components::Uppy < Phlexi::Form::Components::Input
|
246
|
+
# Automatic features:
|
247
|
+
# - Interactive preview of existing attachments
|
248
|
+
# - Delete buttons for removing attachments
|
249
|
+
# - Support for direct cloud uploads
|
250
|
+
# - File type and size validation via Uppy options
|
251
|
+
# ...
|
252
|
+
|
253
|
+
def view_template
|
254
|
+
div(class: "flex flex-col-reverse gap-2") do
|
255
|
+
render_existing_attachments
|
256
|
+
render_upload_interface
|
257
|
+
end
|
258
|
+
end
|
259
|
+
end
|
260
|
+
```
|
261
|
+
:::
|
262
|
+
|
263
|
+
### Secure Association Inputs
|
264
|
+
|
265
|
+
Plutonium overrides all standard Rails association helpers (`belongs_to`, `has_many`, etc.) to use a secure, enhanced version that integrates with [SlimSelect](https://slimselectjs.com/) for a better UI.
|
266
|
+
|
267
|
+
::: code-group
|
268
|
+
```ruby [Association Types]
|
269
|
+
# Automatically used for all standard association types
|
270
|
+
render field(:author).belongs_to_tag
|
271
|
+
render field(:tags).has_many_tag
|
272
|
+
render field(:profile).has_one_tag
|
273
|
+
render field(:commentable).polymorphic_belongs_to_tag
|
274
|
+
```
|
275
|
+
|
276
|
+
```ruby [With Options]
|
277
|
+
render field(:category).belongs_to_tag(
|
278
|
+
choices: Category.published.pluck(:name, :id),
|
279
|
+
add_action: new_category_path, # Adds a "+" button to add new records
|
280
|
+
skip_authorization: false # Enforces authorization policies
|
281
|
+
)
|
282
|
+
```
|
283
|
+
:::
|
284
|
+
|
285
|
+
::: details Security & Implementation
|
286
|
+
The `SecureAssociation` component is the cornerstone of Plutonium's form security.
|
287
|
+
- **SGID Encoding**: It uses `to_signed_global_id` as the value method, so raw database IDs are never exposed to the client.
|
288
|
+
- **Authorization**: It uses `authorized_resource_scope` to ensure that the choices presented to the user are only the ones they are permitted to see.
|
289
|
+
- **Add Action**: It can render an "add new" button that automatically includes a `return_to` parameter for a smooth UX.
|
290
|
+
|
291
|
+
```ruby
|
292
|
+
class Plutonium::UI::Form::Components::SecureAssociation
|
293
|
+
def choices
|
294
|
+
collection = if @skip_authorization
|
295
|
+
# ...
|
296
|
+
else
|
297
|
+
# Only show records user is authorized to see
|
298
|
+
authorized_resource_scope(association_reflection.klass,
|
299
|
+
relation: choices_from_association(association_reflection.klass))
|
300
|
+
end
|
301
|
+
# ...
|
302
|
+
end
|
303
|
+
end
|
304
|
+
```
|
305
|
+
:::
|
306
|
+
|
307
|
+
## Type Inference System
|
308
|
+
|
309
|
+
Plutonium is smart about choosing the right input for a given field, minimizing boilerplate in your forms.
|
310
|
+
|
311
|
+
### Automatic Component Selection
|
312
|
+
|
313
|
+
The `InferredTypes` module overrides the default type inference to map common types to Plutonium's enhanced components.
|
314
|
+
|
315
|
+
```ruby
|
316
|
+
module Plutonium::UI::Form::Options::InferredTypes
|
317
|
+
private
|
318
|
+
|
319
|
+
def infer_field_component
|
320
|
+
case inferred_field_type
|
321
|
+
when :rich_text
|
322
|
+
return :markdown # Use Easymde for ActionText fields
|
323
|
+
end
|
324
|
+
|
325
|
+
inferred = super
|
326
|
+
case inferred
|
327
|
+
when :select
|
328
|
+
:slim_select # Enhance selects with SlimSelect
|
329
|
+
when :date, :time, :datetime
|
330
|
+
:flatpickr # Use Flatpickr for date/time fields
|
331
|
+
else
|
332
|
+
inferred
|
333
|
+
end
|
334
|
+
end
|
335
|
+
end
|
336
|
+
```
|
337
|
+
|
338
|
+
This means you often don't need to specify the input type at all.
|
339
|
+
|
340
|
+
```ruby
|
341
|
+
# These are automatically inferred:
|
342
|
+
render field(:title) # -> input (string)
|
343
|
+
render field(:content) # -> easymde (rich_text)
|
344
|
+
render field(:published_at) # -> flatpickr (datetime)
|
345
|
+
render field(:phone) # -> int_tel_input (tel)
|
346
|
+
render field(:author) # -> secure_association (belongs_to)
|
347
|
+
render field(:avatar) # -> uppy (Active Storage attachment)
|
348
|
+
render field(:category) # -> slim_select (enum/select)
|
349
|
+
```
|
350
|
+
|
351
|
+
## Nested Resources
|
352
|
+
|
353
|
+
Plutonium has first-class support for `accepts_nested_attributes_for`, allowing you to build complex forms with nested records. This is handled by the `RendersNestedResourceFields` concern in `Form::Resource`.
|
354
|
+
|
355
|
+
### Defining Nested Inputs
|
356
|
+
|
357
|
+
You define nested inputs in your resource definition file. Plutonium will automatically detect the configuration from your Rails model's `accepts_nested_attributes_for` declaration—including options like `allow_destroy`, `update_only`, and `limit`—and use them to render the appropriate form controls.
|
358
|
+
|
359
|
+
You can declare a nested input with a simple block or by referencing another definition class.
|
360
|
+
|
361
|
+
::: code-group
|
362
|
+
```ruby [Block Definition]
|
363
|
+
# app/models/post.rb
|
364
|
+
class Post < ApplicationRecord
|
365
|
+
has_many :comments
|
366
|
+
accepts_nested_attributes_for :comments, allow_destroy: true, limit: 5
|
367
|
+
end
|
368
|
+
|
369
|
+
# app/definitions/post_definition.rb
|
370
|
+
class PostDefinition < Plutonium::Resource::Definition
|
371
|
+
# This automatically inherits allow_destroy: true and limit: 5 from the model
|
372
|
+
nested_input :comments do |n|
|
373
|
+
n.input :content, as: :textarea
|
374
|
+
n.input :author_name, as: :string
|
375
|
+
end
|
376
|
+
end
|
377
|
+
```
|
378
|
+
|
379
|
+
```ruby [Reference Definition]
|
380
|
+
# app/models/post.rb
|
381
|
+
class Post < ApplicationRecord
|
382
|
+
has_many :tags
|
383
|
+
accepts_nested_attributes_for :tags, update_only: true
|
384
|
+
end
|
385
|
+
|
386
|
+
# app/definitions/post_definition.rb
|
387
|
+
class PostDefinition < Plutonium::Resource::Definition
|
388
|
+
# This inherits update_only: true from the model
|
389
|
+
nested_input :tags,
|
390
|
+
using: TagDefinition,
|
391
|
+
fields: %i[name color]
|
392
|
+
end
|
393
|
+
```
|
394
|
+
:::
|
395
|
+
|
396
|
+
### Overriding Configuration
|
397
|
+
|
398
|
+
While Plutonium automatically uses your Rails configuration, you can easily override it by passing options directly to the `nested_input` method. Explicit options always take precedence.
|
399
|
+
|
400
|
+
```ruby
|
401
|
+
class PostDefinition < Plutonium::Resource::Definition
|
402
|
+
# Explicit options override the model's configuration
|
403
|
+
nested_input :comments,
|
404
|
+
allow_destroy: false, # Overrides model's allow_destroy: true
|
405
|
+
limit: 10, # Overrides model's limit: 5
|
406
|
+
description: "Add up to 10 comments for this post." do |n|
|
407
|
+
n.input :content
|
408
|
+
end
|
409
|
+
end
|
410
|
+
```
|
411
|
+
|
412
|
+
### Automatic Rendering
|
413
|
+
|
414
|
+
The `Form::Resource` class automatically renders the nested form based on your definition:
|
415
|
+
- For `has_many` associations, it provides "Add" and "Remove" buttons, respecting the `limit`.
|
416
|
+
- For `has_one` and `belongs_to` associations, it renders inline fields for a single record.
|
417
|
+
- If `allow_destroy: true`, a "Delete" checkbox is rendered for persisted records.
|
418
|
+
- If `update_only: true`, the "Add" button is hidden.
|
419
|
+
|
420
|
+
::: details Nested Rendering Internals
|
421
|
+
The `render_nested_resource_field` method orchestrates the rendering of the nested form, including the header, existing records, the "add" button, and the template for new records. This is all managed by the `nested-resource-form-fields` Stimulus controller.
|
422
|
+
:::
|
423
|
+
|
424
|
+
## Theming
|
425
|
+
|
426
|
+
Forms are styled using a comprehensive theme system that leverages Tailwind CSS utility classes. The theme is defined in `lib/plutonium/ui/form/theme.rb`.
|
427
|
+
|
428
|
+
::: details Form Theme Configuration
|
429
|
+
The `Plutonium::UI::Form::Theme.theme` method returns a hash where keys represent form elements (like `input`, `label`, `error`) and values are the corresponding CSS classes. It includes styles for layout, inputs in different states (valid, invalid), and all custom components.
|
430
|
+
|
431
|
+
```ruby
|
432
|
+
class Plutonium::UI::Form::Theme < Phlexi::Form::Theme
|
433
|
+
def self.theme
|
434
|
+
super.merge({
|
435
|
+
# Layout
|
436
|
+
base: "relative bg-white dark:bg-gray-800 shadow-md sm:rounded-lg my-3 p-6 space-y-6",
|
437
|
+
fields_wrapper: "grid grid-cols-1 md:grid-cols-2 2xl:grid-cols-4 gap-4",
|
438
|
+
actions_wrapper: "flex justify-end space-x-2",
|
439
|
+
|
440
|
+
# Input styling
|
441
|
+
input: "w-full p-2 border rounded-md shadow-sm dark:bg-gray-700 focus:ring-2",
|
442
|
+
valid_input: "bg-green-50 border-green-500 ...",
|
443
|
+
invalid_input: "bg-red-50 border-red-500 ...",
|
444
|
+
|
445
|
+
# Enhanced component themes (aliases to base styles)
|
446
|
+
flatpickr: :input,
|
447
|
+
int_tel_input: :input,
|
448
|
+
uppy: :file,
|
449
|
+
association: :select,
|
450
|
+
# ...
|
451
|
+
})
|
452
|
+
end
|
453
|
+
end
|
454
|
+
```
|
455
|
+
:::
|
456
|
+
|
457
|
+
## JavaScript & Stimulus
|
458
|
+
|
459
|
+
Interactivity is powered by a set of dedicated Stimulus controllers. Plutonium automatically loads these controllers and the required third-party libraries.
|
460
|
+
|
461
|
+
- **`form`**: The main controller for handling pre-submit refreshes (for conditional fields).
|
462
|
+
- **`nested-resource-form-fields`**: Manages adding and removing nested form fields dynamically.
|
463
|
+
- **`slim-select`**: Initializes the SlimSelect library on select fields.
|
464
|
+
- **`easymde`**, **`flatpickr`**, **`intl-tel-input`**: Controllers for their respective input components.
|
465
|
+
- **`attachment-input`** & **`attachment-preview`**: Work together to manage the Uppy file upload experience.
|