plutonium 0.54.0 → 0.55.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/.claude/skills/plutonium-behavior/SKILL.md +22 -0
- data/.claude/skills/plutonium-resource/SKILL.md +55 -0
- data/.claude/skills/plutonium-ui/SKILL.md +2 -1
- data/CHANGELOG.md +14 -0
- data/app/assets/plutonium.css +1 -1
- data/app/assets/plutonium.js +18 -0
- data/app/assets/plutonium.js.map +4 -4
- data/app/assets/plutonium.min.js +30 -30
- data/app/assets/plutonium.min.js.map +4 -4
- data/docs/public/images/reference/structured-inputs-removed.png +0 -0
- data/docs/public/images/reference/structured-inputs.png +0 -0
- data/docs/reference/resource/definition.md +110 -0
- data/docs/superpowers/plans/2026-06-02-structured-inputs.md +1061 -0
- data/docs/superpowers/plans/2026-06-02-structured-inputs.md.tasks.json +60 -0
- data/docs/superpowers/specs/2026-06-01-structured-inputs-design.md +191 -0
- data/gemfiles/rails_8.1.gemfile.lock +1 -1
- data/lib/plutonium/definition/base.rb +1 -0
- data/lib/plutonium/definition/structured_inputs.rb +67 -0
- data/lib/plutonium/interaction/README.md +24 -78
- data/lib/plutonium/interaction/base.rb +10 -2
- data/lib/plutonium/resource/controller.rb +6 -1
- data/lib/plutonium/resource/controllers/interactive_actions.rb +10 -6
- data/lib/plutonium/structured_inputs/param_cleaner.rb +36 -0
- data/lib/plutonium/structured_inputs/params_concern.rb +36 -0
- data/lib/plutonium/ui/form/concerns/renders_nested_resource_fields.rb +3 -3
- data/lib/plutonium/ui/form/concerns/renders_structured_inputs.rb +178 -0
- data/lib/plutonium/ui/form/concerns/repeater_field_styles.rb +24 -0
- data/lib/plutonium/ui/form/resource.rb +4 -1
- data/lib/plutonium/ui/modal/slideover.rb +9 -3
- data/lib/plutonium/version.rb +1 -1
- data/package.json +1 -1
- data/src/css/components.css +10 -5
- data/src/js/controllers/register_controllers.js +2 -0
- data/src/js/controllers/structured_input_row_controller.js +26 -0
- metadata +14 -5
- data/docs/superpowers/specs/2026-06-01-interaction-repeater-inputs-design.md +0 -178
- data/lib/plutonium/interaction/nested_attributes.rb +0 -93
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: ecf3e56a7d08f87ee2e77af368b4059655aeea666fcfefcf238256ae8564a9e8
|
|
4
|
+
data.tar.gz: d70895506dda46cafc6933b9a972261365cdbddaff728e6eb8ad84bb3857ce0a
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: d8e6d17854893f67732bfb97ecc7cf744501d5469df99bfd0c3e5c9b8f39d16818c93c270e586f6cd486c4559465db33e4e3cdfb6fff0fa9dfb7d3cf027678ef
|
|
7
|
+
data.tar.gz: af4b9df9e92dd343c6db4d73d39d3cfcad6a08fc3a9ce74ad47afabfb25056c0bccc7e8a924ac3a6070e4767a7e05e69d012cff6073732c04bae425bc33dd894
|
|
@@ -656,6 +656,28 @@ attribute :date, :datetime
|
|
|
656
656
|
|
|
657
657
|
The presence of `:resource` / `:resources` / neither determines the action type — see [[plutonium-resource]] › Action Types.
|
|
658
658
|
|
|
659
|
+
### Structured / repeating input
|
|
660
|
+
|
|
661
|
+
To collect a structured object or a repeating list of field-groups, use
|
|
662
|
+
`structured_input` (it declares the backing attribute for you):
|
|
663
|
+
|
|
664
|
+
```ruby
|
|
665
|
+
structured_input :address do |f| # single → execute sees { street:, city: }
|
|
666
|
+
f.input :street
|
|
667
|
+
f.input :city
|
|
668
|
+
end
|
|
669
|
+
|
|
670
|
+
structured_input :contacts, repeat: 3 do |f| # repeater → [ { label:, phone: }, ... ]
|
|
671
|
+
f.input :label
|
|
672
|
+
f.input :phone
|
|
673
|
+
end
|
|
674
|
+
```
|
|
675
|
+
|
|
676
|
+
⚠️ **`nested_input` and `accepts_nested_attributes_for` are NOT available on
|
|
677
|
+
interactions** (they were model-backed). Use `structured_input` instead — it's
|
|
678
|
+
classless and collects plain hashes/arrays. See [[plutonium-resource]] ›
|
|
679
|
+
Structured Inputs for options (`repeat:`, `using:`, `fields:`).
|
|
680
|
+
|
|
659
681
|
## Inputs
|
|
660
682
|
|
|
661
683
|
Same DSL as definition `input` (load [[plutonium-resource]] for the full list of `as:` types, options, dynamic blocks, etc.):
|
|
@@ -684,6 +684,61 @@ end
|
|
|
684
684
|
- For custom class names, use `class_name:` in the model and `using:` in the definition.
|
|
685
685
|
- `update_only: true` hides the Add button.
|
|
686
686
|
|
|
687
|
+
## Structured Inputs
|
|
688
|
+
|
|
689
|
+
`structured_input` collects a **classless** group of fields — a single hash, or
|
|
690
|
+
(with `repeat:`) an array of hashes. No association or model class is involved.
|
|
691
|
+
On resources the value is stored in a **JSON/jsonb column**; use it when you
|
|
692
|
+
want structured data in a JSON column rather than a real association (which is
|
|
693
|
+
`nested_input`'s job).
|
|
694
|
+
|
|
695
|
+
```ruby
|
|
696
|
+
class Spec < ResourceRecord
|
|
697
|
+
# t.json :payload / t.json :rows (jsonb in production)
|
|
698
|
+
end
|
|
699
|
+
|
|
700
|
+
class SpecDefinition < ResourceDefinition
|
|
701
|
+
structured_input :payload do |f| # single → { title:, notes: }
|
|
702
|
+
f.input :title
|
|
703
|
+
f.input :notes
|
|
704
|
+
end
|
|
705
|
+
|
|
706
|
+
structured_input :rows, repeat: 5 do |f| # repeater → [ { key:, value: }, ... ] (max 5)
|
|
707
|
+
f.input :key
|
|
708
|
+
f.input :value
|
|
709
|
+
end
|
|
710
|
+
end
|
|
711
|
+
|
|
712
|
+
class SpecPolicy < ResourcePolicy
|
|
713
|
+
# NOTE: unlike nested_input, you DO permit the column name here.
|
|
714
|
+
# (update inherits permitted_attributes_for_create automatically.)
|
|
715
|
+
def permitted_attributes_for_create = [:payload, :rows]
|
|
716
|
+
end
|
|
717
|
+
```
|
|
718
|
+
|
|
719
|
+
`execute`/the record sees `payload => { "title" => …, "notes" => … }` and
|
|
720
|
+
`rows => [ { "key" => …, "value" => … }, … ]` (string keys from the JSON column;
|
|
721
|
+
blank rows are dropped, `_destroy` stripped).
|
|
722
|
+
|
|
723
|
+
### Options
|
|
724
|
+
|
|
725
|
+
| Option | Description |
|
|
726
|
+
|--------|-------------|
|
|
727
|
+
| `repeat` | Presence ⇒ array (repeater). `Integer` = max rows; `true` = default cap (10); absent = single hash |
|
|
728
|
+
| `using` | A fields definition class instead of a block |
|
|
729
|
+
| `fields` | Subset of fields from the referenced definition |
|
|
730
|
+
|
|
731
|
+
### Gotchas
|
|
732
|
+
|
|
733
|
+
- The column must be `json`/`jsonb` (or otherwise hold a hash/array). No model macro is needed — the value assigns directly.
|
|
734
|
+
- **Unlike `nested_input`, you DO permit the column name** in `permitted_attributes_for_*` (it's a regular attribute on a JSON column).
|
|
735
|
+
- `repeat: 1` is "array, max one row" — **not** the single form. Presence of `repeat:` always means an array.
|
|
736
|
+
- Rows are positional plain hashes — **no ids, no per-row class, no type coercion**.
|
|
737
|
+
- **No automatic validation.** Classless ⇒ nothing to attach `validates` to. `required:` and a select's `choices:` are **client-side only**, not enforced on the server. To enforce, add a model `validate` (resource) or a `validate` on the interaction (ActiveModel, checked before `execute`).
|
|
738
|
+
- **`as: :select` drops unknown values.** If a stored value isn't in `choices:`, the `<select>` renders blank and **saving overwrites it with `nil`** (standard `<select>` behaviour). Keep `choices:` a stable superset or use free text when values can drift.
|
|
739
|
+
- Inside repeater rows, prefer **native** field types (string, number, text, native `select`, checkbox). JS-enhanced inputs (slim-select, flatpickr, easymde, uppy, intl-tel) transform the DOM and may not survive the repeater's clone-by-innerHTML — verify before relying on them.
|
|
740
|
+
- Same DSL works on **interactions** (see [[plutonium-behavior]] › Interactions) — there it backs an ActiveModel attribute reaching `execute`.
|
|
741
|
+
|
|
687
742
|
## File Uploads
|
|
688
743
|
|
|
689
744
|
```ruby
|
|
@@ -302,7 +302,8 @@ end
|
|
|
302
302
|
These all live in the definition layer:
|
|
303
303
|
|
|
304
304
|
- **Pre-submit / dynamic forms** — see [[plutonium-resource]] › Dynamic Forms.
|
|
305
|
-
- **Nested inputs** (`nested_input :variants`) — see [[plutonium-resource]] › Nested Inputs.
|
|
305
|
+
- **Nested inputs** (`nested_input :variants`) — association-backed inline forms; see [[plutonium-resource]] › Nested Inputs.
|
|
306
|
+
- **Structured inputs** (`structured_input :payload`, `structured_input :rows, repeat: 5`) — classless hash / array-of-hashes into a JSON column (resources) or an attribute (interactions); reuses the repeater chrome. See [[plutonium-resource]] › Structured Inputs.
|
|
306
307
|
- **Interaction forms** — interactions define their own `attribute` / `input` and inherit `Plutonium::UI::Form::Interaction`; see [[plutonium-behavior]] › Interactions.
|
|
307
308
|
|
|
308
309
|
---
|
data/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,17 @@
|
|
|
1
|
+
## [0.55.0] - 2026-06-03
|
|
2
|
+
|
|
3
|
+
### 🚀 Features
|
|
4
|
+
|
|
5
|
+
- Structured_input — classless structured & repeater inputs (resources + interactions) (#60)
|
|
6
|
+
|
|
7
|
+
### 🐛 Bug Fixes
|
|
8
|
+
|
|
9
|
+
- *(ui)* Keep modal backdrop static to smooth dialog dismiss
|
|
10
|
+
|
|
11
|
+
### 🧪 Testing
|
|
12
|
+
|
|
13
|
+
- *(dummy)* Land authenticated users on the entity-scoped org portal
|
|
14
|
+
- *(dummy)* Serve the Organization resource in the org portal
|
|
1
15
|
## [0.54.0] - 2026-06-01
|
|
2
16
|
|
|
3
17
|
### 🚀 Features
|