plutonium 0.55.0 → 0.56.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-resource/SKILL.md +21 -2
- data/.claude/skills/plutonium-ui/SKILL.md +15 -2
- data/CHANGELOG.md +31 -0
- data/app/assets/plutonium.css +1 -1
- data/app/assets/plutonium.js +94 -26
- data/app/assets/plutonium.js.map +2 -2
- data/app/assets/plutonium.min.js +9 -9
- data/app/assets/plutonium.min.js.map +3 -3
- data/config/initializers/rabl.rb +16 -0
- data/docs/.vitepress/config.ts +1 -0
- data/docs/public/templates/lite.rb +10 -0
- data/docs/reference/generators/lite.md +65 -0
- data/docs/reference/resource/definition.md +18 -2
- data/docs/reference/ui/assets.md +14 -0
- data/docs/reference/ui/displays.md +27 -1
- data/docs/reference/ui/forms.md +2 -1
- data/docs/reference/ui/layouts.md +33 -0
- data/docs/superpowers/plans/2026-06-04-sqlite-tune-maintenance-generators.md +857 -0
- data/docs/superpowers/plans/2026-06-04-sqlite-tune-maintenance-generators.md.tasks.json +45 -0
- data/docs/superpowers/specs/2026-06-04-sqlite-tune-maintenance-generators-design.md +238 -0
- data/gemfiles/rails_7.gemfile.lock +1 -1
- data/gemfiles/rails_8.0.gemfile.lock +1 -1
- data/gemfiles/rails_8.1.gemfile.lock +1 -1
- data/lib/generators/pu/core/update/update_generator.rb +4 -1
- data/lib/generators/pu/lib/plutonium_generators/concerns/configures_recurring.rb +89 -0
- data/lib/generators/pu/lite/maintenance/maintenance_generator.rb +45 -0
- data/lib/generators/pu/lite/maintenance/templates/app/jobs/sqlite_maintenance_job.rb.tt +60 -0
- data/lib/generators/pu/lite/rails_pulse/rails_pulse_generator.rb +4 -51
- data/lib/generators/pu/lite/rails_pulse/templates/config/initializers/rails_pulse.rb.tt +1 -1
- data/lib/generators/pu/lite/tune/tune_generator.rb +105 -0
- data/lib/plutonium/models/has_cents.rb +10 -0
- data/lib/plutonium/resource/controllers/interactive_actions.rb +19 -2
- data/lib/plutonium/routing/mapper_extensions.rb +5 -0
- data/lib/plutonium/ui/display/base.rb +9 -0
- data/lib/plutonium/ui/display/components/badge.rb +83 -0
- data/lib/plutonium/ui/display/components/boolean.rb +28 -6
- data/lib/plutonium/ui/display/components/currency.rb +50 -0
- data/lib/plutonium/ui/display/options/inferred_types.rb +13 -0
- data/lib/plutonium/ui/display/theme.rb +5 -0
- data/lib/plutonium/ui/form/base.rb +5 -0
- data/lib/plutonium/ui/form/components/toggle.rb +14 -0
- data/lib/plutonium/ui/form/concerns/renders_nested_resource_fields.rb +14 -25
- data/lib/plutonium/ui/form/concerns/renders_repeater_row_controls.rb +67 -0
- data/lib/plutonium/ui/form/concerns/renders_structured_inputs.rb +5 -38
- data/lib/plutonium/ui/form/interaction.rb +7 -2
- data/lib/plutonium/ui/form/options/inferred_types.rb +2 -0
- data/lib/plutonium/ui/form/resource.rb +1 -0
- data/lib/plutonium/ui/form/theme.rb +12 -0
- data/lib/plutonium/ui/grid/card.rb +58 -21
- data/lib/plutonium/ui/layout/icon_rail.rb +29 -9
- data/lib/plutonium/ui/sidebar_menu.rb +29 -0
- data/lib/plutonium/version.rb +1 -1
- data/package.json +1 -1
- data/plutonium.gemspec +5 -4
- data/src/css/components.css +126 -0
- data/src/js/controllers/dirty_form_guard_controller.js +55 -4
- data/src/js/controllers/nested_resource_form_fields_controller.js +35 -12
- data/src/js/controllers/resource_drop_down_controller.js +49 -14
- metadata +19 -6
|
@@ -27,9 +27,16 @@ export default class extends Controller {
|
|
|
27
27
|
|
|
28
28
|
init() {
|
|
29
29
|
if (this.triggerTarget && this.menuTarget && !this.initialized) {
|
|
30
|
+
// Capture a direct reference to the menu node. While open we teleport
|
|
31
|
+
// it to <body> (see show/hide), which moves it out of this controller's
|
|
32
|
+
// scope — so `this.menuTarget` would throw. Remember its home so we can
|
|
33
|
+
// put it back on hide/disconnect.
|
|
34
|
+
this.menu = this.menuTarget
|
|
35
|
+
this.menuHome = { parent: this.menu.parentNode, next: this.menu.nextSibling }
|
|
36
|
+
|
|
30
37
|
// Initialize popper instance
|
|
31
38
|
// Use 'fixed' strategy to escape overflow containers (e.g., table rows)
|
|
32
|
-
this.popperInstance = createPopper(this.triggerTarget, this.
|
|
39
|
+
this.popperInstance = createPopper(this.triggerTarget, this.menu, {
|
|
33
40
|
strategy: 'fixed',
|
|
34
41
|
placement: this.options.placement,
|
|
35
42
|
modifiers: [
|
|
@@ -72,20 +79,46 @@ export default class extends Controller {
|
|
|
72
79
|
// Remove hover event listeners
|
|
73
80
|
if (this.options.triggerType === 'hover') {
|
|
74
81
|
this.triggerTarget.removeEventListener('mouseenter', this.hoverShowTriggerHandler)
|
|
75
|
-
this.
|
|
82
|
+
this.menu.removeEventListener('mouseenter', this.hoverShowMenuHandler)
|
|
76
83
|
this.triggerTarget.removeEventListener('mouseleave', this.hoverHideHandler)
|
|
77
|
-
this.
|
|
84
|
+
this.menu.removeEventListener('mouseleave', this.hoverHideHandler)
|
|
78
85
|
}
|
|
79
86
|
|
|
80
87
|
// Remove click outside listener
|
|
81
88
|
this.removeClickOutsideListener()
|
|
82
89
|
|
|
90
|
+
// Put the menu back where it belongs before we tear down, so a teleported
|
|
91
|
+
// menu isn't orphaned in <body> after the controller goes away. If its
|
|
92
|
+
// home is gone (e.g. turbo swapped the surrounding content), drop it.
|
|
93
|
+
this.restoreMenu()
|
|
94
|
+
if (this.menu.parentNode === document.body) {
|
|
95
|
+
this.menu.remove()
|
|
96
|
+
}
|
|
97
|
+
|
|
83
98
|
// Destroy popper instance
|
|
84
99
|
this.popperInstance.destroy()
|
|
85
100
|
this.initialized = false
|
|
86
101
|
}
|
|
87
102
|
}
|
|
88
103
|
|
|
104
|
+
// Move the menu to <body> so no ancestor's overflow + containing-block
|
|
105
|
+
// (transform/filter/will-change) can clip it. popper's 'fixed' strategy
|
|
106
|
+
// positions relative to the viewport, but painting is still clipped by a
|
|
107
|
+
// transformed, overflow-hidden ancestor (e.g. grid cards) — teleporting
|
|
108
|
+
// sidesteps that entirely.
|
|
109
|
+
teleportMenu() {
|
|
110
|
+
if (this.menu.parentNode !== document.body) {
|
|
111
|
+
document.body.appendChild(this.menu)
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
restoreMenu() {
|
|
116
|
+
const home = this.menuHome
|
|
117
|
+
if (home && home.parent && home.parent.isConnected && this.menu.parentNode !== home.parent) {
|
|
118
|
+
home.parent.insertBefore(this.menu, home.next)
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
|
|
89
122
|
setupEventListeners() {
|
|
90
123
|
// Bind handlers to preserve context
|
|
91
124
|
this.clickHandler = this.toggle.bind(this)
|
|
@@ -103,7 +136,7 @@ export default class extends Controller {
|
|
|
103
136
|
}
|
|
104
137
|
this.hoverHideHandler = () => {
|
|
105
138
|
setTimeout(() => {
|
|
106
|
-
if (!this.
|
|
139
|
+
if (!this.menu.matches(':hover')) {
|
|
107
140
|
this.hide()
|
|
108
141
|
}
|
|
109
142
|
}, this.options.delay)
|
|
@@ -114,9 +147,9 @@ export default class extends Controller {
|
|
|
114
147
|
this.triggerTarget.addEventListener('click', this.clickHandler)
|
|
115
148
|
} else if (this.options.triggerType === 'hover') {
|
|
116
149
|
this.triggerTarget.addEventListener('mouseenter', this.hoverShowTriggerHandler)
|
|
117
|
-
this.
|
|
150
|
+
this.menu.addEventListener('mouseenter', this.hoverShowMenuHandler)
|
|
118
151
|
this.triggerTarget.addEventListener('mouseleave', this.hoverHideHandler)
|
|
119
|
-
this.
|
|
152
|
+
this.menu.addEventListener('mouseleave', this.hoverHideHandler)
|
|
120
153
|
}
|
|
121
154
|
}
|
|
122
155
|
|
|
@@ -140,8 +173,8 @@ export default class extends Controller {
|
|
|
140
173
|
const isFloatingUI = clickedEl.closest('.flatpickr-calendar, .ss-main, .ss-content')
|
|
141
174
|
|
|
142
175
|
if (
|
|
143
|
-
clickedEl !== this.
|
|
144
|
-
!this.
|
|
176
|
+
clickedEl !== this.menu &&
|
|
177
|
+
!this.menu.contains(clickedEl) &&
|
|
145
178
|
!this.triggerTarget.contains(clickedEl) &&
|
|
146
179
|
!isIgnored &&
|
|
147
180
|
!isFloatingUI &&
|
|
@@ -169,9 +202,10 @@ export default class extends Controller {
|
|
|
169
202
|
}
|
|
170
203
|
|
|
171
204
|
show() {
|
|
172
|
-
this.
|
|
173
|
-
this.
|
|
174
|
-
this.
|
|
205
|
+
this.teleportMenu()
|
|
206
|
+
this.menu.classList.remove('hidden')
|
|
207
|
+
this.menu.classList.add('block')
|
|
208
|
+
this.menu.removeAttribute('aria-hidden')
|
|
175
209
|
|
|
176
210
|
// Enable popper event listeners
|
|
177
211
|
this.popperInstance.setOptions((options) => ({
|
|
@@ -188,9 +222,9 @@ export default class extends Controller {
|
|
|
188
222
|
}
|
|
189
223
|
|
|
190
224
|
hide() {
|
|
191
|
-
this.
|
|
192
|
-
this.
|
|
193
|
-
this.
|
|
225
|
+
this.menu.classList.remove('block')
|
|
226
|
+
this.menu.classList.add('hidden')
|
|
227
|
+
this.menu.setAttribute('aria-hidden', 'true')
|
|
194
228
|
|
|
195
229
|
// Disable popper event listeners
|
|
196
230
|
this.popperInstance.setOptions((options) => ({
|
|
@@ -202,6 +236,7 @@ export default class extends Controller {
|
|
|
202
236
|
}))
|
|
203
237
|
|
|
204
238
|
this.removeClickOutsideListener()
|
|
239
|
+
this.restoreMenu()
|
|
205
240
|
this.visible = false
|
|
206
241
|
}
|
|
207
242
|
}
|
metadata
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: plutonium
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.56.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Stefan Froelich
|
|
8
8
|
bindir: exe
|
|
9
9
|
cert_chain: []
|
|
10
|
-
date: 2026-06-
|
|
10
|
+
date: 2026-06-05 00:00:00.000000000 Z
|
|
11
11
|
dependencies:
|
|
12
12
|
- !ruby/object:Gem::Dependency
|
|
13
13
|
name: zeitwerk
|
|
@@ -637,6 +637,7 @@ files:
|
|
|
637
637
|
- docs/reference/behavior/interactions.md
|
|
638
638
|
- docs/reference/behavior/policies.md
|
|
639
639
|
- docs/reference/configuration.md
|
|
640
|
+
- docs/reference/generators/lite.md
|
|
640
641
|
- docs/reference/index.md
|
|
641
642
|
- docs/reference/resource/actions.md
|
|
642
643
|
- docs/reference/resource/definition.md
|
|
@@ -667,6 +668,8 @@ files:
|
|
|
667
668
|
- docs/superpowers/plans/2026-05-15-public-pages-overhaul.md.tasks.json
|
|
668
669
|
- docs/superpowers/plans/2026-06-02-structured-inputs.md
|
|
669
670
|
- docs/superpowers/plans/2026-06-02-structured-inputs.md.tasks.json
|
|
671
|
+
- docs/superpowers/plans/2026-06-04-sqlite-tune-maintenance-generators.md
|
|
672
|
+
- docs/superpowers/plans/2026-06-04-sqlite-tune-maintenance-generators.md.tasks.json
|
|
670
673
|
- docs/superpowers/specs/2026-04-08-plutonium-skills-overhaul-design.md
|
|
671
674
|
- docs/superpowers/specs/2026-04-14-plutonium-testing-design.md
|
|
672
675
|
- docs/superpowers/specs/2026-05-07-ui-layout-overhaul-design.md
|
|
@@ -676,6 +679,7 @@ files:
|
|
|
676
679
|
- docs/superpowers/specs/2026-05-15-public-pages-overhaul-design.md
|
|
677
680
|
- docs/superpowers/specs/2026-05-29-avatar-component-design.md
|
|
678
681
|
- docs/superpowers/specs/2026-06-01-structured-inputs-design.md
|
|
682
|
+
- docs/superpowers/specs/2026-06-04-sqlite-tune-maintenance-generators-design.md
|
|
679
683
|
- esbuild.config.js
|
|
680
684
|
- exe/pug
|
|
681
685
|
- gemfiles/rails_7.gemfile
|
|
@@ -778,6 +782,7 @@ files:
|
|
|
778
782
|
- lib/generators/pu/lib/plutonium_generators/cli.rb
|
|
779
783
|
- lib/generators/pu/lib/plutonium_generators/concerns/actions.rb
|
|
780
784
|
- lib/generators/pu/lib/plutonium_generators/concerns/config.rb
|
|
785
|
+
- lib/generators/pu/lib/plutonium_generators/concerns/configures_recurring.rb
|
|
781
786
|
- lib/generators/pu/lib/plutonium_generators/concerns/configures_sqlite.rb
|
|
782
787
|
- lib/generators/pu/lib/plutonium_generators/concerns/logger.rb
|
|
783
788
|
- lib/generators/pu/lib/plutonium_generators/concerns/mounts_engines.rb
|
|
@@ -790,6 +795,8 @@ files:
|
|
|
790
795
|
- lib/generators/pu/lib/plutonium_generators/model_generator_base.rb
|
|
791
796
|
- lib/generators/pu/lib/plutonium_generators/non_interactive_prompt.rb
|
|
792
797
|
- lib/generators/pu/lite/litestream/litestream_generator.rb
|
|
798
|
+
- lib/generators/pu/lite/maintenance/maintenance_generator.rb
|
|
799
|
+
- lib/generators/pu/lite/maintenance/templates/app/jobs/sqlite_maintenance_job.rb.tt
|
|
793
800
|
- lib/generators/pu/lite/rails_pulse/rails_pulse_generator.rb
|
|
794
801
|
- lib/generators/pu/lite/rails_pulse/templates/config/initializers/rails_pulse.rb.tt
|
|
795
802
|
- lib/generators/pu/lite/setup/setup_generator.rb
|
|
@@ -797,6 +804,7 @@ files:
|
|
|
797
804
|
- lib/generators/pu/lite/solid_cache/solid_cache_generator.rb
|
|
798
805
|
- lib/generators/pu/lite/solid_errors/solid_errors_generator.rb
|
|
799
806
|
- lib/generators/pu/lite/solid_queue/solid_queue_generator.rb
|
|
807
|
+
- lib/generators/pu/lite/tune/tune_generator.rb
|
|
800
808
|
- lib/generators/pu/pkg/package/package_generator.rb
|
|
801
809
|
- lib/generators/pu/pkg/package/templates/.keep
|
|
802
810
|
- lib/generators/pu/pkg/package/templates/app/controllers/resource_controller.rb.tt
|
|
@@ -1084,8 +1092,10 @@ files:
|
|
|
1084
1092
|
- lib/plutonium/ui/display/base.rb
|
|
1085
1093
|
- lib/plutonium/ui/display/components/association.rb
|
|
1086
1094
|
- lib/plutonium/ui/display/components/attachment.rb
|
|
1095
|
+
- lib/plutonium/ui/display/components/badge.rb
|
|
1087
1096
|
- lib/plutonium/ui/display/components/boolean.rb
|
|
1088
1097
|
- lib/plutonium/ui/display/components/color.rb
|
|
1098
|
+
- lib/plutonium/ui/display/components/currency.rb
|
|
1089
1099
|
- lib/plutonium/ui/display/components/markdown.rb
|
|
1090
1100
|
- lib/plutonium/ui/display/components/phlexi_render.rb
|
|
1091
1101
|
- lib/plutonium/ui/display/options/inferred_types.rb
|
|
@@ -1105,8 +1115,10 @@ files:
|
|
|
1105
1115
|
- lib/plutonium/ui/form/components/secure_association.rb
|
|
1106
1116
|
- lib/plutonium/ui/form/components/secure_polymorphic_association.rb
|
|
1107
1117
|
- lib/plutonium/ui/form/components/sticky_footer.rb
|
|
1118
|
+
- lib/plutonium/ui/form/components/toggle.rb
|
|
1108
1119
|
- lib/plutonium/ui/form/components/uppy.rb
|
|
1109
1120
|
- lib/plutonium/ui/form/concerns/renders_nested_resource_fields.rb
|
|
1121
|
+
- lib/plutonium/ui/form/concerns/renders_repeater_row_controls.rb
|
|
1110
1122
|
- lib/plutonium/ui/form/concerns/renders_structured_inputs.rb
|
|
1111
1123
|
- lib/plutonium/ui/form/concerns/repeater_field_styles.rb
|
|
1112
1124
|
- lib/plutonium/ui/form/concerns/typeahead_attributes.rb
|
|
@@ -1239,17 +1251,18 @@ metadata:
|
|
|
1239
1251
|
homepage_uri: https://radioactive-labs.github.io/plutonium-core/
|
|
1240
1252
|
source_code_uri: https://github.com/radioactive-labs/plutonium-core
|
|
1241
1253
|
post_install_message: |
|
|
1242
|
-
|
|
1254
|
+
ℹ️ Plutonium — breaking change introduced in 0.49.0
|
|
1243
1255
|
|
|
1244
|
-
Entity-scoped URL helpers and path params
|
|
1256
|
+
Entity-scoped URL helpers and path params were renamed in 0.49.0 from
|
|
1245
1257
|
`<entity>_scope_*` to `<entity>_scoped_*`.
|
|
1246
1258
|
|
|
1247
1259
|
Examples:
|
|
1248
1260
|
organization_scope_widgets_path → organization_scoped_widgets_path
|
|
1249
1261
|
params[:organization_scope] → params[:organization_scoped]
|
|
1250
1262
|
|
|
1251
|
-
If you
|
|
1252
|
-
redirects, or hand-written links),
|
|
1263
|
+
If you are upgrading from 0.48.0 or earlier and reference these helpers or
|
|
1264
|
+
params directly (e.g. in tests, custom redirects, or hand-written links),
|
|
1265
|
+
update them to the new names.
|
|
1253
1266
|
|
|
1254
1267
|
Apps that only use `resource_url_for` are unaffected.
|
|
1255
1268
|
rdoc_options: []
|