plutonium 0.26.3 → 0.26.4
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.js +121 -26
- data/app/assets/plutonium.js.map +3 -3
- data/app/assets/plutonium.min.js +18 -18
- data/app/assets/plutonium.min.js.map +3 -3
- data/lib/plutonium/version.rb +1 -1
- data/package.json +1 -1
- data/src/js/controllers/attachment_input_controller.js +41 -1
- data/src/js/controllers/easymde_controller.js +45 -6
- data/src/js/controllers/flatpickr_controller.js +24 -8
- data/src/js/controllers/intl_tel_input_controller.js +23 -5
- data/src/js/controllers/slim_select_controller.js +27 -12
- metadata +2 -2
data/lib/plutonium/version.rb
CHANGED
data/package.json
CHANGED
@@ -26,6 +26,8 @@ export default class extends Controller {
|
|
26
26
|
//======= Lifecycle
|
27
27
|
|
28
28
|
connect() {
|
29
|
+
if (this.uppy) return;
|
30
|
+
|
29
31
|
// initialize
|
30
32
|
this.uploadedFiles = []
|
31
33
|
|
@@ -38,10 +40,48 @@ export default class extends Controller {
|
|
38
40
|
this.#buildTriggers()
|
39
41
|
// init state
|
40
42
|
this.#onAttachmentsChanged()
|
43
|
+
|
44
|
+
// Just recreate Uppy after morphing - preserve existing attachments
|
45
|
+
this.element.addEventListener("turbo:morph-element", (event) => {
|
46
|
+
if (event.target === this.element && !this.morphing) {
|
47
|
+
this.morphing = true;
|
48
|
+
requestAnimationFrame(() => {
|
49
|
+
this.#handleMorph();
|
50
|
+
this.morphing = false;
|
51
|
+
});
|
52
|
+
}
|
53
|
+
});
|
41
54
|
}
|
42
55
|
|
43
56
|
disconnect() {
|
44
|
-
this
|
57
|
+
this.#cleanupUppy();
|
58
|
+
}
|
59
|
+
|
60
|
+
#handleMorph() {
|
61
|
+
if (!this.element.isConnected) return;
|
62
|
+
|
63
|
+
// Clean up the old instance
|
64
|
+
this.#cleanupUppy();
|
65
|
+
|
66
|
+
// Recreate everything - Uppy, triggers, etc.
|
67
|
+
this.uploadedFiles = []
|
68
|
+
this.element.style["display"] = "none"
|
69
|
+
this.configureUppy()
|
70
|
+
this.#buildTriggers()
|
71
|
+
this.#onAttachmentsChanged()
|
72
|
+
}
|
73
|
+
|
74
|
+
#cleanupUppy() {
|
75
|
+
if (this.uppy) {
|
76
|
+
this.uppy.destroy();
|
77
|
+
this.uppy = null;
|
78
|
+
}
|
79
|
+
|
80
|
+
// Clean up triggers
|
81
|
+
if (this.triggerContainer && this.triggerContainer.parentNode) {
|
82
|
+
this.triggerContainer.parentNode.removeChild(this.triggerContainer);
|
83
|
+
this.triggerContainer = null;
|
84
|
+
}
|
45
85
|
}
|
46
86
|
|
47
87
|
attachmentPreviewOutletConnected(outlet, element) {
|
@@ -4,21 +4,60 @@ import { marked } from 'marked';
|
|
4
4
|
|
5
5
|
// Connects to data-controller="easymde"
|
6
6
|
export default class extends Controller {
|
7
|
+
static targets = ["textarea"]
|
8
|
+
|
7
9
|
connect() {
|
10
|
+
if (this.easyMDE) return
|
11
|
+
|
12
|
+
this.originalValue = this.element.value
|
8
13
|
this.easyMDE = new EasyMDE(this.#buildOptions())
|
9
|
-
|
14
|
+
|
15
|
+
// Store the editor content before morphing
|
16
|
+
this.element.addEventListener("turbo:before-morph-element", (event) => {
|
17
|
+
if (event.target === this.element && this.easyMDE) {
|
18
|
+
this.storedValue = this.easyMDE.value()
|
19
|
+
}
|
20
|
+
})
|
21
|
+
|
22
|
+
// Restore after morphing
|
23
|
+
this.element.addEventListener("turbo:morph-element", (event) => {
|
24
|
+
if (event.target === this.element) {
|
25
|
+
requestAnimationFrame(() => this.#handleMorph())
|
26
|
+
}
|
27
|
+
})
|
10
28
|
}
|
11
29
|
|
12
30
|
disconnect() {
|
13
31
|
if (this.easyMDE) {
|
14
|
-
|
32
|
+
try {
|
33
|
+
// Only call toTextArea if the element is still in the DOM
|
34
|
+
if (this.element.isConnected && this.element.parentNode) {
|
35
|
+
this.easyMDE.toTextArea()
|
36
|
+
}
|
37
|
+
} catch (error) {
|
38
|
+
console.warn('EasyMDE cleanup error:', error)
|
39
|
+
}
|
15
40
|
this.easyMDE = null
|
16
41
|
}
|
17
42
|
}
|
18
|
-
|
19
|
-
|
20
|
-
this.
|
21
|
-
|
43
|
+
|
44
|
+
#handleMorph() {
|
45
|
+
if (!this.element.isConnected) return
|
46
|
+
|
47
|
+
// Don't call toTextArea during morph - just clean up references
|
48
|
+
if (this.easyMDE) {
|
49
|
+
// Skip toTextArea cleanup - it causes DOM errors during morphing
|
50
|
+
this.easyMDE = null
|
51
|
+
}
|
52
|
+
|
53
|
+
// Recreate the editor
|
54
|
+
this.easyMDE = new EasyMDE(this.#buildOptions())
|
55
|
+
|
56
|
+
// Restore the stored value if we have it
|
57
|
+
if (this.storedValue !== undefined) {
|
58
|
+
this.easyMDE.value(this.storedValue)
|
59
|
+
this.storedValue = undefined
|
60
|
+
}
|
22
61
|
}
|
23
62
|
|
24
63
|
#buildOptions() {
|
@@ -3,14 +3,21 @@ import { Controller } from "@hotwired/stimulus";
|
|
3
3
|
// Connects to data-controller="flatpickr"
|
4
4
|
export default class extends Controller {
|
5
5
|
connect() {
|
6
|
-
this.
|
6
|
+
if (this.picker) return;
|
7
7
|
|
8
|
+
this.modal = document.querySelector("[data-controller=remote-modal]");
|
8
9
|
this.picker = new flatpickr(this.element, this.#buildOptions());
|
9
10
|
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
11
|
+
// Just recreate Flatpickr after morphing - the DOM will have correct value
|
12
|
+
this.element.addEventListener("turbo:morph-element", (event) => {
|
13
|
+
if (event.target === this.element && !this.morphing) {
|
14
|
+
this.morphing = true;
|
15
|
+
requestAnimationFrame(() => {
|
16
|
+
this.#handleMorph();
|
17
|
+
this.morphing = false;
|
18
|
+
});
|
19
|
+
}
|
20
|
+
});
|
14
21
|
}
|
15
22
|
|
16
23
|
disconnect() {
|
@@ -20,9 +27,18 @@ export default class extends Controller {
|
|
20
27
|
}
|
21
28
|
}
|
22
29
|
|
23
|
-
|
24
|
-
this.
|
25
|
-
|
30
|
+
#handleMorph() {
|
31
|
+
if (!this.element.isConnected) return;
|
32
|
+
|
33
|
+
// Clean up the old instance
|
34
|
+
if (this.picker) {
|
35
|
+
this.picker.destroy();
|
36
|
+
this.picker = null;
|
37
|
+
}
|
38
|
+
|
39
|
+
// Recreate the picker - it will pick up the current DOM value
|
40
|
+
this.modal = document.querySelector("[data-controller=remote-modal]");
|
41
|
+
this.picker = new flatpickr(this.element, this.#buildOptions());
|
26
42
|
}
|
27
43
|
|
28
44
|
#buildOptions() {
|
@@ -12,10 +12,20 @@ export default class extends Controller {
|
|
12
12
|
}
|
13
13
|
|
14
14
|
inputTargetConnected() {
|
15
|
-
if (!this.hasInputTarget) return;
|
15
|
+
if (!this.hasInputTarget || this.iti) return;
|
16
16
|
|
17
17
|
this.iti = window.intlTelInput(this.inputTarget, this.#buildOptions())
|
18
|
-
|
18
|
+
|
19
|
+
// Just recreate IntlTelInput after morphing - the DOM will have correct value
|
20
|
+
this.element.addEventListener("turbo:morph-element", (event) => {
|
21
|
+
if (event.target === this.element && !this.morphing) {
|
22
|
+
this.morphing = true;
|
23
|
+
requestAnimationFrame(() => {
|
24
|
+
this.#handleMorph();
|
25
|
+
this.morphing = false;
|
26
|
+
});
|
27
|
+
}
|
28
|
+
});
|
19
29
|
}
|
20
30
|
|
21
31
|
inputTargetDisconnected() {
|
@@ -25,9 +35,17 @@ export default class extends Controller {
|
|
25
35
|
}
|
26
36
|
}
|
27
37
|
|
28
|
-
|
29
|
-
this.
|
30
|
-
|
38
|
+
#handleMorph() {
|
39
|
+
if (!this.inputTarget || !this.inputTarget.isConnected) return;
|
40
|
+
|
41
|
+
// Clean up the old instance
|
42
|
+
if (this.iti) {
|
43
|
+
this.iti.destroy();
|
44
|
+
this.iti = null;
|
45
|
+
}
|
46
|
+
|
47
|
+
// Recreate the intl tel input - it will pick up the current DOM value
|
48
|
+
this.iti = window.intlTelInput(this.inputTarget, this.#buildOptions());
|
31
49
|
}
|
32
50
|
|
33
51
|
#buildOptions() {
|
@@ -3,6 +3,19 @@ import { Controller } from "@hotwired/stimulus";
|
|
3
3
|
// Connects to data-controller="slim-select"
|
4
4
|
export default class extends Controller {
|
5
5
|
connect() {
|
6
|
+
if (this.slimSelect) return;
|
7
|
+
|
8
|
+
this.#setupSlimSelect();
|
9
|
+
|
10
|
+
// Just recreate SlimSelect after morphing - the DOM will have correct selections
|
11
|
+
this.element.addEventListener("turbo:morph-element", (event) => {
|
12
|
+
if (event.target === this.element) {
|
13
|
+
requestAnimationFrame(() => this.#handleMorph());
|
14
|
+
}
|
15
|
+
});
|
16
|
+
}
|
17
|
+
|
18
|
+
#setupSlimSelect() {
|
6
19
|
const settings = {};
|
7
20
|
const modal = document.querySelector('[data-controller="remote-modal"]');
|
8
21
|
|
@@ -48,11 +61,6 @@ export default class extends Controller {
|
|
48
61
|
|
49
62
|
// Add mutation observer to track aria-expanded attribute
|
50
63
|
this.setupAriaObserver();
|
51
|
-
|
52
|
-
this.element.setAttribute(
|
53
|
-
"data-action",
|
54
|
-
"turbo:morph-element->slim-select#reconnect"
|
55
|
-
);
|
56
64
|
}
|
57
65
|
|
58
66
|
handleDropdownPosition() {
|
@@ -162,6 +170,20 @@ export default class extends Controller {
|
|
162
170
|
}
|
163
171
|
|
164
172
|
disconnect() {
|
173
|
+
this.#cleanupSlimSelect();
|
174
|
+
}
|
175
|
+
|
176
|
+
#handleMorph() {
|
177
|
+
if (!this.element.isConnected) return;
|
178
|
+
|
179
|
+
// Clean up the old instance without DOM manipulation
|
180
|
+
this.#cleanupSlimSelect();
|
181
|
+
|
182
|
+
// Recreate the select - it will automatically pick up the current DOM selections
|
183
|
+
this.#setupSlimSelect();
|
184
|
+
}
|
185
|
+
|
186
|
+
#cleanupSlimSelect() {
|
165
187
|
// Clean up event listeners
|
166
188
|
if (this.element) {
|
167
189
|
if (this.boundHandleDropdownOpen) {
|
@@ -208,11 +230,4 @@ export default class extends Controller {
|
|
208
230
|
this.modifiedSelectWrapper = null;
|
209
231
|
}
|
210
232
|
}
|
211
|
-
|
212
|
-
reconnect() {
|
213
|
-
this.disconnect();
|
214
|
-
// dispatch this on the next frame.
|
215
|
-
// there's some funny issue where my elements get removed from the DOM
|
216
|
-
setTimeout(() => this.connect(), 10);
|
217
|
-
}
|
218
233
|
}
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: plutonium
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.26.
|
4
|
+
version: 0.26.4
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Stefan Froelich
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2025-07-
|
11
|
+
date: 2025-07-30 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: zeitwerk
|