katalyst-kpop 2.0.9 → 3.0.0.beta.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (62) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +17 -43
  3. data/app/assets/builds/katalyst/kpop.esm.js +599 -0
  4. data/app/assets/builds/katalyst/kpop.js +479 -519
  5. data/app/assets/builds/katalyst/kpop.min.js +2 -1
  6. data/app/assets/builds/katalyst/kpop.min.js.map +1 -0
  7. data/app/assets/builds/katalyst/kpop.umd.js +5890 -0
  8. data/app/assets/config/kpop.js +1 -1
  9. data/app/assets/stylesheets/katalyst/kpop/_frame.scss +104 -0
  10. data/app/assets/stylesheets/katalyst/kpop/_modal.scss +95 -0
  11. data/app/assets/stylesheets/katalyst/kpop/_scrim.scss +33 -3
  12. data/app/assets/stylesheets/katalyst/kpop/_side_panel.scss +64 -0
  13. data/app/assets/stylesheets/katalyst/kpop/_variables.scss +25 -0
  14. data/app/assets/stylesheets/katalyst/kpop.scss +6 -1
  15. data/app/components/concerns/kpop/has_html_attributes.rb +78 -0
  16. data/app/components/kpop/frame_component.html.erb +14 -0
  17. data/app/components/kpop/frame_component.rb +45 -0
  18. data/app/components/kpop/modal/title_component.html.erb +6 -0
  19. data/app/components/kpop/modal/title_component.rb +28 -0
  20. data/app/components/kpop/modal_component.html.erb +8 -0
  21. data/app/components/kpop/modal_component.rb +39 -0
  22. data/app/components/scrim_component.rb +32 -0
  23. data/app/helpers/kpop_helper.rb +12 -35
  24. data/app/javascript/kpop/application.js +15 -0
  25. data/app/javascript/kpop/controllers/close_controller.js +9 -0
  26. data/app/javascript/kpop/controllers/frame_controller.js +189 -0
  27. data/app/javascript/kpop/controllers/modal_controller.js +30 -0
  28. data/app/javascript/kpop/controllers/redirect_controller.js +22 -0
  29. data/app/{assets/javascripts → javascript/kpop}/controllers/scrim_controller.js +76 -72
  30. data/app/javascript/kpop/debug.js +3 -0
  31. data/app/javascript/kpop/modals/content_modal.js +46 -0
  32. data/app/javascript/kpop/modals/frame_modal.js +41 -0
  33. data/app/javascript/kpop/modals/modal.js +69 -0
  34. data/app/javascript/kpop/modals/stream_modal.js +49 -0
  35. data/app/javascript/kpop/modals/stream_renderer.js +15 -0
  36. data/app/views/layouts/kpop.html.erb +1 -1
  37. data/config/importmap.rb +1 -4
  38. data/lib/katalyst/kpop/engine.rb +13 -12
  39. data/lib/katalyst/kpop/matchers/base.rb +18 -0
  40. data/lib/katalyst/kpop/matchers/capybara_matcher.rb +46 -0
  41. data/lib/katalyst/kpop/matchers/capybara_parser.rb +17 -0
  42. data/lib/katalyst/kpop/matchers/chained_matcher.rb +40 -0
  43. data/lib/katalyst/kpop/matchers/frame_matcher.rb +16 -0
  44. data/lib/katalyst/kpop/matchers/modal_matcher.rb +20 -0
  45. data/lib/katalyst/kpop/matchers/redirect_finder.rb +16 -0
  46. data/lib/katalyst/kpop/matchers/redirect_matcher.rb +28 -0
  47. data/lib/katalyst/kpop/matchers/response_matcher.rb +33 -0
  48. data/lib/katalyst/kpop/matchers/stream_matcher.rb +16 -0
  49. data/lib/katalyst/kpop/matchers/title_finder.rb +16 -0
  50. data/lib/katalyst/kpop/matchers/title_matcher.rb +28 -0
  51. data/lib/katalyst/kpop/matchers.rb +79 -0
  52. data/lib/katalyst/kpop/turbo.rb +56 -0
  53. data/lib/katalyst/kpop/version.rb +1 -1
  54. data/lib/katalyst/kpop.rb +4 -0
  55. metadata +90 -15
  56. data/app/assets/builds/katalyst/kpop.css +0 -117
  57. data/app/assets/javascripts/controllers/kpop_controller.js +0 -72
  58. data/app/assets/javascripts/katalyst/kpop.js +0 -9
  59. data/app/assets/stylesheets/katalyst/kpop/_index.scss +0 -2
  60. data/app/assets/stylesheets/katalyst/kpop/_kpop.scss +0 -133
  61. data/app/helpers/kpop/modal.rb +0 -98
  62. data/app/helpers/scrim_helper.rb +0 -13
@@ -1 +1 @@
1
- //= link_tree ../javascripts/controllers
1
+ //= link_tree ../builds
@@ -0,0 +1,104 @@
1
+ @use "variables" as *;
2
+
3
+ .kpop--container {
4
+ display: none;
5
+
6
+ position: fixed;
7
+ left: 0;
8
+ top: 0;
9
+ right: 0;
10
+ bottom: 0;
11
+
12
+ align-items: center;
13
+ z-index: 100;
14
+ pointer-events: none;
15
+
16
+ > * {
17
+ pointer-events: auto;
18
+ }
19
+ }
20
+
21
+ .kpop--frame {
22
+ --opening-animation: slide-in-up;
23
+ --closing-animation: slide-out-down;
24
+
25
+ position: relative;
26
+ display: grid;
27
+ overflow: hidden;
28
+ margin: 0 auto;
29
+
30
+ --min-width: #{$min-width};
31
+ --max-width: #{$max-width};
32
+ --min-height: #{$min-height};
33
+ --max-height: #{$max-height};
34
+
35
+ min-width: var(--min-width);
36
+ max-width: var(--max-width);
37
+ min-height: var(--min-height);
38
+ max-height: var(--max-height);
39
+
40
+ grid-template-columns: min(var(--max-width), max(var(--min-width), 100%));
41
+ grid-template-rows: min(var(--max-height), max(var(--min-height), 100%));
42
+ }
43
+
44
+ @media (max-width: $mobile-width), (max-height: $mobile-height) {
45
+ .kpop--frame {
46
+ --min-width: 100vw;
47
+ --max-width: 100vw;
48
+ --min-height: 50vh;
49
+ --max-height: calc(100vh - 1.5rem);
50
+ }
51
+ }
52
+
53
+ .scrim[data-scrim-open-value="false"] + .kpop--container .kpop--frame {
54
+ display: none;
55
+ }
56
+
57
+ .scrim[data-hide-animating]
58
+ + .kpop--container
59
+ .kpop--frame[data-kpop--frame-open-value="true"] {
60
+ animation: var(--closing-animation);
61
+ animation-duration: $duration;
62
+ animation-fill-mode: forwards;
63
+ }
64
+
65
+ .scrim[data-show-animating] + .kpop--container .kpop--frame {
66
+ animation: var(--opening-animation);
67
+ animation-duration: $duration;
68
+ animation-fill-mode: forwards;
69
+ }
70
+
71
+ .kpop-modal.iframe {
72
+ .kpop-content {
73
+ overflow: unset;
74
+ }
75
+
76
+ iframe {
77
+ height: $max-height;
78
+ width: $max-width;
79
+ flex-grow: 1;
80
+ overflow: scroll;
81
+ }
82
+ }
83
+
84
+ @keyframes slide-in-up {
85
+ 0% {
86
+ transform: translateY(10%);
87
+ opacity: 0;
88
+ }
89
+ 100% {
90
+ transform: translateY(0%);
91
+ opacity: 1;
92
+ }
93
+ }
94
+
95
+ @keyframes slide-out-down {
96
+ 0% {
97
+ transform: translateY(0%);
98
+ opacity: 1;
99
+ }
100
+ 100% {
101
+ transform: translateY(10%);
102
+ opacity: 0;
103
+ }
104
+ }
@@ -0,0 +1,95 @@
1
+ @use "variables" as *;
2
+
3
+ .kpop-modal {
4
+ display: grid;
5
+ grid-template-areas:
6
+ "title-bar"
7
+ "header"
8
+ "content"
9
+ "footer";
10
+ grid-template-rows: auto auto 1fr auto;
11
+
12
+ background-color: white;
13
+ border: 1px solid black;
14
+ border-radius: $border-radius;
15
+ }
16
+
17
+ .kpop-title-bar {
18
+ grid-area: title-bar;
19
+ display: flex;
20
+ background: $title-background-color;
21
+ color: $title-text-color;
22
+
23
+ .kpop-title {
24
+ padding: $default-padding;
25
+ flex-grow: 1;
26
+ }
27
+
28
+ .kpop-close {
29
+ background: none;
30
+ border: none;
31
+ color: $title-text-color;
32
+ cursor: pointer;
33
+ display: block;
34
+ font-size: 2rem;
35
+ font-weight: bold;
36
+ padding: 0 0.75rem;
37
+ text-decoration: none;
38
+ }
39
+ }
40
+
41
+ .kpop-header {
42
+ grid-area: header;
43
+ }
44
+
45
+ .kpop-content {
46
+ grid-area: content;
47
+ display: flex;
48
+ flex-direction: column;
49
+ overflow: auto;
50
+ }
51
+
52
+ .kpop-footer {
53
+ grid-area: footer;
54
+ background: white;
55
+ border-top: 1px solid black;
56
+ padding: $default-padding;
57
+ }
58
+
59
+ .kpop-buttons {
60
+ display: flex;
61
+ gap: 0.5rem;
62
+ justify-content: space-between;
63
+ }
64
+
65
+ .kpop-modal.iframe {
66
+ .kpop-content {
67
+ overflow: unset;
68
+ }
69
+
70
+ iframe {
71
+ height: $max-height;
72
+ width: $max-width;
73
+ flex-grow: 1;
74
+ overflow: scroll;
75
+ }
76
+ }
77
+
78
+ @include mobile {
79
+ .kpop-modal {
80
+ border-radius: 0;
81
+ border: none;
82
+ }
83
+
84
+ .kpop-modal.iframe {
85
+ iframe {
86
+ width: 100%;
87
+ height: 100%;
88
+ }
89
+ }
90
+
91
+ .kpop-buttons {
92
+ flex-direction: column-reverse;
93
+ text-align: center;
94
+ }
95
+ }
@@ -1,16 +1,46 @@
1
+ @use "variables" as *;
2
+
1
3
  .scrim {
2
4
  position: fixed;
3
5
  top: 0;
4
6
  bottom: 0;
5
7
  left: 0;
6
8
  right: 0;
7
- background: rgba(0, 0, 0, 0.6);
9
+ background: $scrim-background;
8
10
  z-index: -1;
9
- transition: opacity 0.2s ease-in-out, z-index 0.2s step-end;
10
11
  opacity: 0;
12
+
13
+ &[data-hide-animating] {
14
+ animation: fade-out;
15
+ animation-duration: $duration;
16
+ animation-fill-mode: forwards;
17
+ }
18
+
19
+ &[data-show-animating] {
20
+ animation: fade-in;
21
+ animation-duration: $duration;
22
+ animation-fill-mode: forwards;
23
+ }
11
24
  }
12
25
 
13
26
  .scrim[data-scrim-open-value="true"] {
14
27
  opacity: 1;
15
- transition: opacity 0.2s ease-in-out, z-index 0.2s step-start;
28
+ }
29
+
30
+ @keyframes fade-in {
31
+ 0% {
32
+ opacity: 0;
33
+ }
34
+ 100% {
35
+ opacity: 1;
36
+ }
37
+ }
38
+
39
+ @keyframes fade-out {
40
+ 0% {
41
+ opacity: 1;
42
+ }
43
+ 100% {
44
+ opacity: 0;
45
+ }
16
46
  }
@@ -0,0 +1,64 @@
1
+ @use "variables" as *;
2
+
3
+ .kpop--frame.side-panel {
4
+ --opening-animation: slide-in-right;
5
+ --closing-animation: slide-out-right;
6
+ --min-width: 30vw;
7
+ --max-width: 50vw;
8
+ --min-height: 100vh;
9
+ --max-height: 100vh;
10
+
11
+ margin-inline: auto 0;
12
+ align-self: flex-end;
13
+
14
+ @include mobile {
15
+ & {
16
+ --opening-animation: slide-in-bottom;
17
+ --closing-animation: slide-out-bottom;
18
+ --min-width: 100vw;
19
+ --max-width: 100vw;
20
+ --min-height: 50vh;
21
+ --max-height: calc(100vh - 1.5rem);
22
+ }
23
+ }
24
+
25
+ .kpop-modal {
26
+ border-radius: 0;
27
+ }
28
+ }
29
+
30
+ @keyframes slide-in-right {
31
+ 0% {
32
+ transform: translateX(100%);
33
+ }
34
+ 100% {
35
+ transform: translateX(0%);
36
+ }
37
+ }
38
+
39
+ @keyframes slide-out-right {
40
+ 0% {
41
+ transform: translateX(0%);
42
+ }
43
+ 100% {
44
+ transform: translateX(100%);
45
+ }
46
+ }
47
+
48
+ @keyframes slide-in-bottom {
49
+ 0% {
50
+ transform: translateY(100%);
51
+ }
52
+ 100% {
53
+ transform: translateY(0%);
54
+ }
55
+ }
56
+
57
+ @keyframes slide-out-bottom {
58
+ 0% {
59
+ transform: translateY(0%);
60
+ }
61
+ 100% {
62
+ transform: translateY(100%);
63
+ }
64
+ }
@@ -0,0 +1,25 @@
1
+ // frame variables
2
+ $min-width: 35rem !default;
3
+ $max-width: 52rem !default;
4
+ $min-height: 30vh !default;
5
+ $max-height: 80vh !default;
6
+ $duration: 0.2s !default;
7
+
8
+ // breakpoints
9
+ $mobile-width: 600px !default;
10
+ $mobile-height: 400px !default;
11
+
12
+ @mixin mobile {
13
+ @media (max-width: $mobile-width), (max-height: $mobile-height) {
14
+ @content;
15
+ }
16
+ }
17
+
18
+ // modal variables
19
+ $border-radius: 0.5rem !default;
20
+ $title-background-color: #344055 !default;
21
+ $title-text-color: white !default;
22
+ $default-padding: 1rem 1.5rem !default;
23
+
24
+ // scrim variables
25
+ $scrim-background: rgba(0, 0, 0, 0.6) !default;
@@ -1 +1,6 @@
1
- @use "kpop/index";
1
+ @forward "kpop/variables";
2
+
3
+ @use "kpop/scrim";
4
+ @use "kpop/frame";
5
+ @use "kpop/side_panel";
6
+ @use "kpop/modal";
@@ -0,0 +1,78 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "html_attributes_utils"
4
+
5
+ module Kpop
6
+ # Adds HTML attributes to a component.
7
+ # Accepts HTML attributes from the constructor or via `html_attributes=`.
8
+ # These are merged with the default attributes defined in the component.
9
+ # Adds support for custom html attributes for other tags, e.g.:
10
+ # define_html_attribute_methods :table_attributes, default: {}
11
+ # tag.table(**table_attributes)
12
+ module HasHtmlAttributes
13
+ extend ActiveSupport::Concern
14
+
15
+ using HTMLAttributesUtils
16
+
17
+ MERGEABLE_ATTRIBUTES = [
18
+ *HTMLAttributesUtils::DEFAULT_MERGEABLE_ATTRIBUTES,
19
+ %i[data controller],
20
+ %i[data action],
21
+ ].freeze
22
+
23
+ FLATTENABLE_ATTRIBUTES = [
24
+ %i[data controller],
25
+ %i[data action],
26
+ ].freeze
27
+
28
+ refine NilClass do
29
+ def flatten_html(*)
30
+ self
31
+ end
32
+ end
33
+
34
+ refine Hash do
35
+ def merge_html(attributes)
36
+ result = deep_merge_html_attributes(attributes, mergeable_attributes: MERGEABLE_ATTRIBUTES)
37
+ FLATTENABLE_ATTRIBUTES.each_with_object(result) do |path, flattened|
38
+ flattened.flatten_html(*path)
39
+ end
40
+ end
41
+
42
+ def flatten_html(key, *path)
43
+ if path.empty?
44
+ self[key] = self[key].join(" ") if self[key].is_a?(Array)
45
+ else
46
+ self[key].flatten_html(*path)
47
+ end
48
+ end
49
+ end
50
+
51
+ class_methods do
52
+ using HasHtmlAttributes
53
+
54
+ def define_html_attribute_methods(name, default: {})
55
+ define_method("default_#{name}") { default }
56
+ private("default_#{name}")
57
+
58
+ define_method(name) do
59
+ send("default_#{name}").merge_html(instance_variable_get("@#{name}") || {})
60
+ end
61
+
62
+ define_method("#{name}=") do |options|
63
+ instance_variable_set("@#{name}", options.slice(:id, :aria, :class, :data).merge(options.fetch(:html, {})))
64
+ end
65
+ end
66
+ end
67
+
68
+ included do
69
+ define_html_attribute_methods :html_attributes, default: {}
70
+ end
71
+
72
+ def initialize(**options)
73
+ super(**options.except(:id, :aria, :class, :data, :html))
74
+
75
+ self.html_attributes = options
76
+ end
77
+ end
78
+ end
@@ -0,0 +1,14 @@
1
+ <div class="kpop--container">
2
+ <%= turbo_frame_tag(id, **html_attributes) do %>
3
+ <%= content %>
4
+ <% if flash[:kpop] %>
5
+ <%= tag.div("", data: {
6
+ controller: "kpop--redirect",
7
+ kpop__redirect_kpop__frame_outlet: "##{id}",
8
+ kpop__redirect_path_value: flash[:kpop],
9
+ kpop__redirect_target_value: id,
10
+ turbo_temporary: "",
11
+ }) %>
12
+ <% end %>
13
+ <% end %>
14
+ </div>
@@ -0,0 +1,45 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Kpop
4
+ class FrameComponent < ViewComponent::Base
5
+ include HasHtmlAttributes
6
+ include Turbo::FramesHelper
7
+
8
+ attr_reader :id
9
+
10
+ ACTIONS = %w[
11
+ popstate@window->kpop--frame#popstate
12
+ scrim:dismiss@window->kpop--frame#dismiss
13
+ scrim:hide@window->kpop--frame#dismiss
14
+ turbo:before-frame-render->kpop--frame#beforeFrameRender
15
+ turbo:before-visit@window->kpop--frame#beforeVisit
16
+ turbo:frame-load->kpop--frame#frameLoad
17
+ ].freeze
18
+
19
+ def initialize(id: "kpop", scrim: "#scrim", **)
20
+ super
21
+
22
+ @id = id
23
+ @scrim = scrim
24
+ end
25
+
26
+ def inspect
27
+ "#<#{self.class.name} id: #{id.inspect}>"
28
+ end
29
+
30
+ private
31
+
32
+ def default_html_attributes
33
+ {
34
+ class: "kpop--frame",
35
+ data: {
36
+ controller: "kpop--frame",
37
+ action: ACTIONS.join(" "),
38
+ "kpop--frame-scrim-outlet": @scrim,
39
+ turbo_action: "advance",
40
+ },
41
+ target: "_top",
42
+ }
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,6 @@
1
+ <%= tag.div(class: "kpop-title-bar", **html_attributes) do %>
2
+ <span class="kpop-title"><%= title %></span>
3
+ <% unless captive? %>
4
+ <button class="kpop-close" data-action="click->kpop--frame#dismiss:prevent">×</button>
5
+ <% end %>
6
+ <% end %>
@@ -0,0 +1,28 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Kpop
4
+ module Modal
5
+ class TitleComponent < ViewComponent::Base
6
+ include HasHtmlAttributes
7
+
8
+ def initialize(title: nil, captive: false, **)
9
+ super
10
+
11
+ @title = title
12
+ @captive = captive
13
+ end
14
+
15
+ def title
16
+ content? ? content : @title
17
+ end
18
+
19
+ def captive?
20
+ @captive
21
+ end
22
+
23
+ def inspect
24
+ "#<#{self.class.name} title: #{title.inspect}>"
25
+ end
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,8 @@
1
+ <%= tag.div(**html_attributes) do %>
2
+ <%= title if title? %>
3
+ <%= header if header? %>
4
+ <div class="kpop-content">
5
+ <%= content %>
6
+ </div>
7
+ <%= footer if footer? %>
8
+ <% end %>
@@ -0,0 +1,39 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Kpop
4
+ class ModalComponent < ViewComponent::Base
5
+ include HasHtmlAttributes
6
+
7
+ renders_one :title, "Kpop::Modal::TitleComponent"
8
+ renders_one :header
9
+ renders_one :footer
10
+
11
+ def initialize(title:, captive: false, fallback_location: nil, layout: nil, **)
12
+ super
13
+
14
+ @fallback_location = fallback_location
15
+ @layout = layout
16
+
17
+ # Generate a title bar. This can be overridden by calling title_bar again.
18
+ with_title(title:, captive:) if title.present?
19
+ end
20
+
21
+ def inspect
22
+ "#<#{self.class.name} title: #{title.inspect}>"
23
+ end
24
+
25
+ private
26
+
27
+ def default_html_attributes
28
+ {
29
+ class: "kpop-modal",
30
+ data: {
31
+ controller: "kpop--modal",
32
+ "kpop--modal-current-location-value": request.path,
33
+ "kpop--modal-fallback-location-value": @fallback_location,
34
+ "kpop--modal-layout-value": @layout&.to_s&.dasherize,
35
+ },
36
+ }
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,32 @@
1
+ # frozen_string_literal: true
2
+
3
+ class ScrimComponent < ViewComponent::Base
4
+ attr_reader :id, :z_index
5
+
6
+ ACTIONS = %w[
7
+ click->scrim#dismiss
8
+ keyup@window->scrim#escape
9
+ ].freeze
10
+
11
+ def initialize(id: "scrim", z_index: 40)
12
+ super
13
+
14
+ @id = id
15
+ @z_index = z_index
16
+ end
17
+
18
+ def call
19
+ tag.div(id:,
20
+ class: "scrim",
21
+ data: {
22
+ controller: "scrim",
23
+ scrim_z_index_value: z_index,
24
+ turbo_permanent: "",
25
+ action: ACTIONS.join(" "),
26
+ })
27
+ end
28
+
29
+ def inspect
30
+ "#<#{self.class.name} id: #{id.inspect}>"
31
+ end
32
+ end
@@ -1,55 +1,32 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module KpopHelper
4
- # Render a modal dialog. Intended for use inside a kpop turbo frame tag.
5
- # See builder for options.
6
- def render_kpop(options = {}, &block)
7
- Kpop::Modal.new(self).render(options, &block)
8
- end
9
-
10
- # Render a turbo stream action that will dismiss any open kpop modals.
11
- def dismiss_kpop
12
- turbo_stream.update("kpop", "")
13
- end
14
-
15
- # Render a turbo frame tag that can be targeted for rendering kpop modals.
16
- def kpop_frame_tag(**html_attributes, &block)
17
- html_attributes[:class] ||= "kpop-container"
18
- html_attributes[:data] ||= {}
19
- html_attributes[:data][:controller] = "kpop"
20
- html_attributes[:data][:action] = "scrim:hide@window->kpop#dismiss"
21
-
22
- turbo_frame_tag("kpop", **html_attributes) do
23
- capture(&block) if block
24
- end
25
- end
4
+ using HTMLAttributesUtils
26
5
 
27
6
  # Renders a link that will navigate the kpop turbo frame to the given URL.
28
7
  # The URL should render a modal response inside a kpop frame tag.
29
- def kpop_link_to(name = nil, options = nil, html_options = nil, &block)
30
- default_html_options = {
31
- data: { turbo: true, turbo_frame: "kpop" },
32
- }
8
+ def kpop_link_to(name = nil, options = nil, html_attributes = nil, &block)
9
+ default_html_attributes = { data: { turbo_frame: "kpop" } }
33
10
  if block
34
11
  # Param[name] is the path for the link
35
- link_to(name, default_html_options.deep_merge(options || {}), &block)
12
+ link_to(name, default_html_attributes.deep_merge_html_attributes(options || {}), &block)
36
13
  else
37
- link_to(name, options, default_html_options.deep_merge(html_options || {}))
14
+ link_to(name, options, default_html_attributes.deep_merge_html_attributes(html_attributes || {}))
38
15
  end
39
16
  end
40
17
 
41
18
  # Renders a button that will navigate the kpop turbo frame to the given URL.
42
19
  # The URL should render a modal response inside a kpop frame tag.
43
- def kpop_button_to(name = nil, options = nil, html_options = nil, &block)
44
- default_html_options = {
45
- form: { data: { turbo: true, turbo_frame: "kpop" } },
20
+ def kpop_button_to(name = nil, options = nil, html_attributes = nil, &)
21
+ default_html_attributes = {
22
+ form: { data: { turbo_frame: "kpop" } },
46
23
  }
47
- button_to(name, options, default_html_options.deep_merge(html_options || {}), &block)
24
+ button_to(name, options, default_html_attributes.deep_merge_html_attributes(html_attributes || {}), &)
48
25
  end
49
26
 
50
27
  # Renders a button that will close the current kpop modal, if any.
51
- def kpop_button_close(content = nil, **options, &block)
52
- content = block ? capture(yield) : content
53
- tag.button content, data: { action: "click->kpop#dismiss:prevent" }, **options
28
+ def kpop_button_close(content = nil, **, &block)
29
+ content = capture(yield) if block
30
+ tag.button(content, data: { action: "click->kpop--frame#dismiss:prevent" }, **)
54
31
  end
55
32
  end
@@ -0,0 +1,15 @@
1
+ import CloseController from "../kpop/controllers/close_controller";
2
+ import FrameController from "../kpop/controllers/frame_controller";
3
+ import ModalController from "../kpop/controllers/modal_controller";
4
+ import RedirectController from "../kpop/controllers/redirect_controller";
5
+ import ScrimController from "../kpop/controllers/scrim_controller";
6
+
7
+ const Definitions = [
8
+ { identifier: "kpop--close", controllerConstructor: CloseController },
9
+ { identifier: "kpop--frame", controllerConstructor: FrameController },
10
+ { identifier: "kpop--modal", controllerConstructor: ModalController },
11
+ { identifier: "kpop--redirect", controllerConstructor: RedirectController },
12
+ { identifier: "scrim", controllerConstructor: ScrimController },
13
+ ];
14
+
15
+ export { Definitions as default };