@radioactive-labs/plutonium 0.1.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.
Files changed (36) hide show
  1. package/LICENSE.txt +21 -0
  2. package/README.md +91 -0
  3. package/package.json +47 -0
  4. package/src/css/plutonium.css +3 -0
  5. package/src/dist/css/plutonium.css +1 -0
  6. package/src/dist/js/plutonium.js +12417 -0
  7. package/src/dist/js/plutonium.js.map +7 -0
  8. package/src/dist/js/plutonium.min.js +39 -0
  9. package/src/dist/js/plutonium.min.js.map +7 -0
  10. package/src/js/controllers/color_mode_controller.js +41 -0
  11. package/src/js/controllers/form_controller.js +13 -0
  12. package/src/js/controllers/frame_navigator_controller.js +99 -0
  13. package/src/js/controllers/has_many_panel_controller.js +8 -0
  14. package/src/js/controllers/interactive_action_form_controller.js +13 -0
  15. package/src/js/controllers/nav_grid_menu_controller.js +8 -0
  16. package/src/js/controllers/nav_grid_menu_item_controller.js +8 -0
  17. package/src/js/controllers/nav_user_controller.js +8 -0
  18. package/src/js/controllers/nav_user_link_controller.js +8 -0
  19. package/src/js/controllers/nav_user_section_controller.js +8 -0
  20. package/src/js/controllers/nested_resource_form_fields_controller.js +64 -0
  21. package/src/js/controllers/register_controllers.js +45 -0
  22. package/src/js/controllers/resource_dismiss_controller.js +39 -0
  23. package/src/js/controllers/resource_drop_down_controller.js +31 -0
  24. package/src/js/controllers/resource_header_controller.js +8 -0
  25. package/src/js/controllers/resource_layout_controller.js +8 -0
  26. package/src/js/controllers/sidebar_menu_controller.js +8 -0
  27. package/src/js/controllers/sidebar_menu_item_controller.js +8 -0
  28. package/src/js/controllers/table_controller.js +8 -0
  29. package/src/js/controllers/table_search_input_controller.js +8 -0
  30. package/src/js/controllers/table_toolbar_controller.js +8 -0
  31. package/src/js/controllers/toolbar_controller.js +8 -0
  32. package/src/js/core.js +4 -0
  33. package/src/js/turbo/index.js +5 -0
  34. package/src/js/turbo/turbo_actions.js +8 -0
  35. package/src/js/turbo/turbo_debug.js +30 -0
  36. package/src/js/turbo/turbo_frame_monkey_patch.js +23 -0
@@ -0,0 +1,41 @@
1
+ import { Controller } from "@hotwired/stimulus"
2
+
3
+
4
+ // Connects to data-controller="color-mode"
5
+ export default class extends Controller {
6
+ // static targets = ["trigger", "menu"]
7
+
8
+ connect() {
9
+ console.log(`color-mode connected: ${this.element}`)
10
+ this.updateColorMode()
11
+ }
12
+
13
+ disconnect() {
14
+ }
15
+
16
+ updateColorMode() {
17
+ if (localStorage.theme === 'dark' || (!('theme' in localStorage) && window.matchMedia('(prefers-color-scheme: dark)').matches)) {
18
+ document.documentElement.classList.add('dark')
19
+ } else {
20
+ document.documentElement.classList.remove('dark')
21
+ }
22
+ }
23
+
24
+ setLightColorMode() {
25
+ // Whenever the user explicitly chooses light mode
26
+ localStorage.theme = 'light'
27
+ this.updateColorMode()
28
+ }
29
+
30
+ setDarkColorMode() {
31
+ // Whenever the user explicitly chooses dark mode
32
+ localStorage.theme = 'dark'
33
+ this.updateColorMode()
34
+ }
35
+
36
+ setSystemColorMode() {
37
+ // Whenever the user explicitly chooses to respect the OS preference
38
+ localStorage.removeItem('theme')
39
+ this.updateColorMode()
40
+ }
41
+ }
@@ -0,0 +1,13 @@
1
+ import { Controller } from "@hotwired/stimulus"
2
+ import debounce from "lodash.debounce";
3
+
4
+ // Connects to data-controller="form"
5
+ export default class extends Controller {
6
+ connect() {
7
+ console.log(`form connected: ${this.element}`)
8
+ }
9
+
10
+ submit() {
11
+ this.element.requestSubmit()
12
+ }
13
+ }
@@ -0,0 +1,99 @@
1
+ import { Controller } from "@hotwired/stimulus"
2
+
3
+ // Connects to data-controller="frame-navigator"
4
+ export default class extends Controller {
5
+ static targets = ["frame", "refreshButton", "backButton", "homeButton"];
6
+
7
+ connect() {
8
+ console.log(`frame-navigator connected: ${this.element}`)
9
+
10
+ this.srcHistory = []
11
+ this.originalFrameSrc = this.frameTarget.src
12
+
13
+ if (this.hasRefreshButtonTarget) {
14
+ this.refreshButtonTarget.style.display = ''
15
+ this.refreshButtonClicked = this.refreshButtonClicked.bind(this);
16
+ this.refreshButtonTarget.addEventListener("click", this.refreshButtonClicked);
17
+ }
18
+
19
+ if (this.hasBackButtonTarget) {
20
+ this.backButtonClicked = this.backButtonClicked.bind(this);
21
+ this.backButtonTarget.addEventListener("click", this.backButtonClicked);
22
+ }
23
+
24
+ if (this.hasHomeButtonTarget) {
25
+ this.homeButtonClicked = this.homeButtonClicked.bind(this);
26
+ this.homeButtonTarget.addEventListener("click", this.homeButtonClicked);
27
+ }
28
+
29
+ this.frameLoaded = this.frameLoaded.bind(this);
30
+ this.frameTarget.addEventListener("turbo:frame-load", this.frameLoaded);
31
+
32
+ this.frameLoading = this.frameLoading.bind(this);
33
+ this.frameTarget.addEventListener("turbo:click", this.frameLoading);
34
+ this.frameTarget.addEventListener("turbo:submit-start", this.frameLoading);
35
+ }
36
+
37
+ disconnect() {
38
+ if (this.hasRefreshButtonTarget) this.refreshButtonTarget.removeEventListener("click", this.refreshButtonClicked);
39
+ if (this.hasBackButtonTarget) this.backButtonTarget.removeEventListener("click", this.backButtonClicked);
40
+ if (this.hasHomeButtonTarget) this.homeButtonTarget.removeEventListener("click", this.homeButtonClicked);
41
+
42
+ this.frameTarget.removeEventListener("turbo:frame-load", this.frameLoaded);
43
+ this.frameTarget.removeEventListener("turbo:click", this.frameLoading);
44
+ this.frameTarget.removeEventListener("turbo:submit-start", this.frameLoading);
45
+ }
46
+
47
+ frameLoading(event) {
48
+ if (this.hasRefreshButtonTarget) this.refreshButtonTarget.classList.add("motion-safe:animate-spin")
49
+ this.frameTarget.classList.add("motion-safe:animate-pulse")
50
+ }
51
+
52
+ frameLoaded(event) {
53
+ if (this.hasRefreshButtonTarget) this.refreshButtonTarget.classList.remove("motion-safe:animate-spin")
54
+ this.frameTarget.classList.remove("motion-safe:animate-pulse")
55
+
56
+ let src = event.target.src
57
+ if (src == this.currentSrc) {
58
+ // this must be a refresh
59
+ // do nothing
60
+ }
61
+ else if (src == this.originalFrameSrc)
62
+ this.srcHistory = [src]
63
+ else
64
+ this.srcHistory.push(src)
65
+
66
+ this.updateNavigationButtonsDisplay()
67
+ }
68
+
69
+ refreshButtonClicked(event) {
70
+ this.frameLoading(null)
71
+
72
+ this.frameTarget.reload()
73
+ }
74
+
75
+ backButtonClicked(event) {
76
+ this.frameLoading(null)
77
+
78
+ this.srcHistory.pop()
79
+ this.frameTarget.src = this.currentSrc
80
+ }
81
+
82
+ homeButtonClicked(event) {
83
+ this.frameLoading(null)
84
+
85
+ this.frameTarget.src = this.originalFrameSrc
86
+ }
87
+
88
+ get currentSrc() { return this.srcHistory[this.srcHistory.length - 1] }
89
+
90
+ updateNavigationButtonsDisplay() {
91
+ if (this.hasHomeButtonTarget) {
92
+ this.homeButtonTarget.style.display = this.srcHistory.length > 1 ? '' : 'none'
93
+ }
94
+
95
+ if (this.hasBackButtonTarget) {
96
+ this.backButtonTarget.style.display = this.srcHistory.length > 2 ? '' : 'none'
97
+ }
98
+ }
99
+ }
@@ -0,0 +1,8 @@
1
+ import { Controller } from "@hotwired/stimulus"
2
+
3
+ // Connects to data-controller="has-many-panel"
4
+ export default class extends Controller {
5
+ connect() {
6
+ console.log(`has-many-panel connected: ${this.element}`)
7
+ }
8
+ }
@@ -0,0 +1,13 @@
1
+ import { Controller } from "@hotwired/stimulus"
2
+ import debounce from "lodash.debounce";
3
+
4
+ // Connects to data-controller="interactive-action-form"
5
+ export default class extends Controller {
6
+ connect() {
7
+ console.log(`interactive-action-form connected: ${this.element}`)
8
+ }
9
+
10
+ submit() {
11
+ this.element.requestSubmit()
12
+ }
13
+ }
@@ -0,0 +1,8 @@
1
+ import { Controller } from "@hotwired/stimulus"
2
+
3
+ // Connects to data-controller="nav-grid-menu"
4
+ export default class extends Controller {
5
+ connect() {
6
+ console.log(`nav-grid-menu connected: ${this.element}`)
7
+ }
8
+ }
@@ -0,0 +1,8 @@
1
+ import { Controller } from "@hotwired/stimulus"
2
+
3
+ // Connects to data-controller="nav-grid-menu-item"
4
+ export default class extends Controller {
5
+ connect() {
6
+ console.log(`nav-grid-menu-item connected: ${this.element}`)
7
+ }
8
+ }
@@ -0,0 +1,8 @@
1
+ import { Controller } from "@hotwired/stimulus"
2
+
3
+ // Connects to data-controller="nav-user"
4
+ export default class extends Controller {
5
+ connect() {
6
+ console.log(`nav-user connected: ${this.element}`)
7
+ }
8
+ }
@@ -0,0 +1,8 @@
1
+ import { Controller } from "@hotwired/stimulus"
2
+
3
+ // Connects to data-controller="nav-user-link"
4
+ export default class extends Controller {
5
+ connect() {
6
+ console.log(`nav-user-link connected: ${this.element}`)
7
+ }
8
+ }
@@ -0,0 +1,8 @@
1
+ import { Controller } from "@hotwired/stimulus"
2
+
3
+ // Connects to data-controller="nav-user-section"
4
+ export default class extends Controller {
5
+ connect() {
6
+ console.log(`nav-user-section connected: ${this.element}`)
7
+ }
8
+ }
@@ -0,0 +1,64 @@
1
+ import { Controller } from "@hotwired/stimulus"
2
+
3
+ // Connects to data-controller="nested-resource-form-fields"
4
+ // Copied from https://github.com/stimulus-components/stimulus-rails-nested-form/blob/master/src/index.ts
5
+ export default class extends Controller {
6
+ static targets = ["target", "template", "addButton"]
7
+
8
+ static values = {
9
+ wrapperSelector: {
10
+ type: String,
11
+ default: ".nested-resource-form-fields",
12
+ },
13
+ limit: Number,
14
+ }
15
+
16
+ connect() {
17
+ this.updateState()
18
+ }
19
+
20
+ add(e) {
21
+ e.preventDefault()
22
+
23
+ const content = this.templateTarget.innerHTML.replace(/NEW_RECORD/g, new Date().getTime().toString())
24
+ this.targetTarget.insertAdjacentHTML("beforebegin", content)
25
+
26
+ const event = new CustomEvent("nested-resource-form-fields:add", { bubbles: true })
27
+ this.element.dispatchEvent(event)
28
+
29
+ this.updateState()
30
+ }
31
+
32
+ remove(e) {
33
+ e.preventDefault()
34
+
35
+ const wrapper = e.target.closest(this.wrapperSelectorValue)
36
+
37
+ if (wrapper.dataset.newRecord === "true") {
38
+ wrapper.remove()
39
+ } else {
40
+ wrapper.style.display = "none"
41
+
42
+ const input = wrapper.querySelector("input[name*='_destroy']")
43
+ input.value = "1"
44
+ }
45
+
46
+ const event = new CustomEvent("nested-resource-form-fields:remove", { bubbles: true })
47
+ this.element.dispatchEvent(event)
48
+
49
+ this.updateState()
50
+ }
51
+
52
+ updateState() {
53
+ if (!this.hasAddButtonTarget || this.limitValue == 0) return
54
+
55
+ if (this.childCount >= this.limitValue)
56
+ this.addButtonTarget.style.display = "none"
57
+ else
58
+ this.addButtonTarget.style.display = "initial"
59
+ }
60
+
61
+ get childCount() {
62
+ return this.element.querySelectorAll(this.wrapperSelectorValue).length
63
+ }
64
+ }
@@ -0,0 +1,45 @@
1
+ // Import controllers here
2
+ import ResourceLayoutController from "./resource_layout_controller.js"
3
+ import NavGridMenuItemController from "./nav_grid_menu_item_controller.js"
4
+ import NavGridMenuController from "./nav_grid_menu_controller.js"
5
+ import NavUserSectionController from "./nav_user_section_controller.js"
6
+ import NavUserLinkController from "./nav_user_link_controller.js"
7
+ import NavUserController from "./nav_user_controller.js"
8
+ import ResourceHeaderController from "./resource_header_controller.js"
9
+ import SidebarMenuItemController from "./sidebar_menu_item_controller.js"
10
+ import SidebarMenuController from "./sidebar_menu_controller.js"
11
+ import HasManyPanelController from "./has_many_panel_controller.js"
12
+ import NestedResourceFormFieldsController from "./nested_resource_form_fields_controller.js"
13
+ import ToolbarController from "./toolbar_controller.js"
14
+ import TableSearchInputController from "./table_search_input_controller.js"
15
+ import TableToolbarController from "./table_toolbar_controller.js"
16
+ import TableController from "./table_controller.js"
17
+ import FormController from "./form_controller.js"
18
+ import ResourceDropDownController from "./resource_drop_down_controller.js"
19
+ import ResourceDismissController from "./resource_dismiss_controller.js"
20
+ import FrameNavigatorController from "./frame_navigator_controller.js"
21
+ import ColorModeController from "./color_mode_controller.js"
22
+
23
+ export default function (application) {
24
+ // Register controllers here
25
+ application.register("resource-layout", ResourceLayoutController)
26
+ application.register("nav-grid-menu-item", NavGridMenuItemController)
27
+ application.register("nav-grid-menu", NavGridMenuController)
28
+ application.register("nav-user-section", NavUserSectionController)
29
+ application.register("nav-user-link", NavUserLinkController)
30
+ application.register("nav-user", NavUserController)
31
+ application.register("resource-header", ResourceHeaderController)
32
+ application.register("sidebar-menu-item", SidebarMenuItemController)
33
+ application.register("sidebar-menu", SidebarMenuController)
34
+ application.register("has-many-panel", HasManyPanelController)
35
+ application.register("nested-resource-form-fields", NestedResourceFormFieldsController)
36
+ application.register("toolbar", ToolbarController)
37
+ application.register("table-search-input", TableSearchInputController)
38
+ application.register("table-toolbar", TableToolbarController)
39
+ application.register("table", TableController)
40
+ application.register("form", FormController)
41
+ application.register("resource-drop-down", ResourceDropDownController)
42
+ application.register("resource-dismiss", ResourceDismissController)
43
+ application.register("frame-navigator", FrameNavigatorController)
44
+ application.register("color-mode", ColorModeController)
45
+ }
@@ -0,0 +1,39 @@
1
+ import { Controller } from "@hotwired/stimulus"
2
+ import { Dismiss } from 'flowbite';
3
+
4
+
5
+ // Connects to data-controller="resource-dismiss"
6
+ export default class extends Controller {
7
+ static targets = ["trigger", "target"]
8
+
9
+ static values = {
10
+ after: Number,
11
+ }
12
+
13
+ connect() {
14
+ console.log(`resource-dismiss connected: ${this.element}`)
15
+
16
+ // https://flowbite.com/docs/components/alerts/#javascript-behaviour
17
+ this.dismiss = new Dismiss(this.targetTarget, this.triggerTarget);
18
+
19
+ console.log(this.hasAfterValue)
20
+ console.log(this.afterValue)
21
+ if (this.hasAfterValue && this.afterValue > 0) {
22
+ this.autoDismissTimeout = setTimeout(() => {
23
+ this.hide()
24
+ this.autoDismissTimeout = null
25
+ }, this.afterValue);
26
+ }
27
+ }
28
+
29
+ disconnect() {
30
+ if (this.autoDismissTimeout) clearTimeout(this.autoDismissTimeout)
31
+
32
+ this.dismiss = null
33
+ this.autoDismissTimeout = null
34
+ }
35
+
36
+ hide() {
37
+ this.dismiss.hide()
38
+ }
39
+ }
@@ -0,0 +1,31 @@
1
+ import { Controller } from "@hotwired/stimulus"
2
+ import { Dropdown } from 'flowbite';
3
+
4
+
5
+ // Connects to data-controller="resource-drop-down"
6
+ export default class extends Controller {
7
+ static targets = ["trigger", "menu"]
8
+
9
+ connect() {
10
+ console.log(`resource-drop-down connected: ${this.element}`)
11
+
12
+ // https://flowbite.com/docs/components/dropdowns/#javascript-behaviour
13
+ this.dropdown = new Dropdown(this.menuTarget, this.triggerTarget);
14
+ }
15
+
16
+ disconnect() {
17
+ this.dropdown = null
18
+ }
19
+
20
+ toggle() {
21
+ this.dropdown.toggle()
22
+ }
23
+
24
+ show() {
25
+ this.dropdown.show()
26
+ }
27
+
28
+ hide() {
29
+ this.dropdown.show()
30
+ }
31
+ }
@@ -0,0 +1,8 @@
1
+ import { Controller } from "@hotwired/stimulus"
2
+
3
+ // Connects to data-controller="resource-header"
4
+ export default class extends Controller {
5
+ connect() {
6
+ console.log(`resource-header connected: ${this.element}`)
7
+ }
8
+ }
@@ -0,0 +1,8 @@
1
+ import { Controller } from "@hotwired/stimulus"
2
+
3
+ // Connects to data-controller="resource-layout"
4
+ export default class extends Controller {
5
+ connect() {
6
+ console.log(`resource-layout connected: ${this.element}`)
7
+ }
8
+ }
@@ -0,0 +1,8 @@
1
+ import { Controller } from "@hotwired/stimulus"
2
+
3
+ // Connects to data-controller="sidebar-menu"
4
+ export default class extends Controller {
5
+ connect() {
6
+ console.log(`sidebar-menu connected: ${this.element}`)
7
+ }
8
+ }
@@ -0,0 +1,8 @@
1
+ import { Controller } from "@hotwired/stimulus"
2
+
3
+ // Connects to data-controller="sidebar-menu-item"
4
+ export default class extends Controller {
5
+ connect() {
6
+ console.log(`sidebar-menu-item connected: ${this.element}`)
7
+ }
8
+ }
@@ -0,0 +1,8 @@
1
+ import { Controller } from "@hotwired/stimulus"
2
+
3
+ // Connects to data-controller="table"
4
+ export default class extends Controller {
5
+ connect() {
6
+ console.log(`table connected: ${this.element}`)
7
+ }
8
+ }
@@ -0,0 +1,8 @@
1
+ import { Controller } from "@hotwired/stimulus"
2
+
3
+ // Connects to data-controller="table-search-input"
4
+ export default class extends Controller {
5
+ connect() {
6
+ console.log(`table-search-input connected: ${this.element}`)
7
+ }
8
+ }
@@ -0,0 +1,8 @@
1
+ import { Controller } from "@hotwired/stimulus"
2
+
3
+ // Connects to data-controller="table-toolbar"
4
+ export default class extends Controller {
5
+ connect() {
6
+ console.log(`table-toolbar connected: ${this.element}`)
7
+ }
8
+ }
@@ -0,0 +1,8 @@
1
+ import { Controller } from "@hotwired/stimulus"
2
+
3
+ // Connects to data-controller="toolbar"
4
+ export default class extends Controller {
5
+ connect() {
6
+ console.log(`toolbar connected: ${this.element}`)
7
+ }
8
+ }
package/src/js/core.js ADDED
@@ -0,0 +1,4 @@
1
+ import registerControllers from "./controllers/register_controllers.js"
2
+
3
+
4
+ export { registerControllers }
@@ -0,0 +1,5 @@
1
+ import * as Turbo from "@hotwired/turbo"
2
+
3
+ import "./turbo_debug"
4
+ // import "./turbo_actions"
5
+ // import "./turbo_frame_monkey_patch"
@@ -0,0 +1,8 @@
1
+ // Add a redirect stream action
2
+ Turbo.StreamActions.redirect = function () {
3
+ // See: https://github.com/hotwired/turbo/issues/554
4
+ Turbo.clearCache();
5
+
6
+ const url = this.getAttribute("url")
7
+ Turbo.visit(url)
8
+ }
@@ -0,0 +1,30 @@
1
+ eventNames = [
2
+ 'turbo:click',
3
+ 'turbo:before-visit',
4
+ 'turbo:visit',
5
+ 'turbo:submit-start',
6
+ 'turbo:before-fetch-request',
7
+ 'turbo:before-fetch-response',
8
+ 'turbo:submit-end',
9
+ 'turbo:before-cache',
10
+ 'turbo:before-render',
11
+ 'turbo:before-stream-render',
12
+ 'turbo:render',
13
+ 'turbo:load',
14
+ 'turbo:before-frame-render',
15
+ 'turbo:frame-render',
16
+ 'turbo:frame-load',
17
+ 'turbo:frame-missing',
18
+ 'turbo:fetch-request-error',
19
+ 'turbo:reload', // https://github.com/hotwired/turbo/pull/556
20
+ 'turbo:morph',
21
+ 'turbo:before-morph-element',
22
+ 'turbo:morph-attribute',
23
+ 'turbo:morph',
24
+ ]
25
+
26
+ eventNames.forEach(eventName => {
27
+ document.addEventListener(eventName, (event) => {
28
+ console.log(event.type, event);
29
+ });
30
+ });
@@ -0,0 +1,23 @@
1
+ // Monkeypatch to fix turbo issue of wrong turbo-frame
2
+ // See: https://github.com/hotwired/turbo/pull/579
3
+ document.addEventListener("turbo:before-fetch-request", (event) => {
4
+ const targetTurboFrame = event.target.getAttribute("data-turbo-frame");
5
+ const fetchTurboFrame = event.detail.fetchOptions.headers["Turbo-Frame"];
6
+ if (
7
+ targetTurboFrame &&
8
+ targetTurboFrame != fetchTurboFrame &&
9
+ document.querySelector(`turbo-frame#${targetTurboFrame}`)
10
+ ) {
11
+ event.detail.fetchOptions.headers["Turbo-Frame"] = targetTurboFrame;
12
+ }
13
+ });
14
+
15
+ // // Reload the entire page if we are missing a frame
16
+ // // See: https://stackoverflow.com/a/75704489/644571
17
+ // document.addEventListener("turbo:frame-missing", (event) => {
18
+ // if (event.target.id != 'modal') return
19
+
20
+ // const { detail: { response, visit } } = event;
21
+ // event.preventDefault();
22
+ // visit(response);
23
+ // });