ultimate_turbo_modal 1.3.1 → 1.4.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: '079b28d06be34aba1359de1c34042f9f2ef131421f37af1a7f3c8619e156e68b'
4
- data.tar.gz: 551d973abd6d0c51f0ad1e01e87ead35697030e4fcce5f62ac591dc09683a284
3
+ metadata.gz: 8d0ae24b41414e4d9419260f7de74789e488a6e0d0a961749e10c3f6ca70ecaf
4
+ data.tar.gz: ef606673fe357af79d46760a2c59252da8052fcd6fdbce56fdf264cd015fe460
5
5
  SHA512:
6
- metadata.gz: 611ce181e6be8833b0b0c094bf2a776edf85dd050ca93fcf866401c1a3e05c0f81c2be519ba2ea8e98efd3ce3b28d7ee0fb2bb6512938a0142149b80fe9ac05e
7
- data.tar.gz: 77159bc4ce94a2bf2cc1abddbc068efe4b5bb3c821494d937262411961c2cfdc0df036fb83ed7dd56f8d25c1743d85d585e572a085f7374d8eecc050ec2bd11a
6
+ metadata.gz: '08ded5bfa9b93dac612301c125c9acd95fae727856154c861971917f3751cd1e11d15f49c9a3b2c00c70ac468c0e19f92a5d69a59158c63d5a826c70322478b2'
7
+ data.tar.gz: 23641e005618db6c5b09cfe64fbc8dad905930ae38bf04cfefcff722d681fc8423c7d39cb70d1cccb6d11743ff4cc9aa8c94c7b13a96d4e82b488d7e0a8fe240
data/CHANGELOG.md CHANGED
@@ -1,3 +1,12 @@
1
+ ## [1.4.0] - 2023-11-23
2
+
3
+ - Added ability to specify custom `data-action` for the close button.
4
+ - Code cleanup, deduplication
5
+
6
+ ## [1.3.1] - 2023-11-23
7
+
8
+ - Bug fixes
9
+
1
10
  ## [1.3.0] - 2023-11-14
2
11
 
3
12
  - Added ability to pass in a `title` block.
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- ultimate_turbo_modal (1.3.1)
4
+ ultimate_turbo_modal (1.4.0)
5
5
  phlex-rails (>= 1.0, < 2.0)
6
6
  rails (>= 7)
7
7
  stimulus-rails
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Phlex
2
4
  module DeferredRenderWithMainContent
3
5
  def template(&)
@@ -1,7 +1,11 @@
1
+ # frozen_string_literal: true
2
+
1
3
  class UltimateTurboModal::Base < Phlex::HTML
2
4
  prepend Phlex::DeferredRenderWithMainContent
3
5
  # @param padding [Boolean] Whether to add padding around the modal content
4
- # @param close_button [Boolean] Whether to show a close button.
6
+ # @param close_button [Boolean] Whether to show a close button
7
+ # @param close_button_sr_label [String] Close button label for screen readers
8
+ # @param close_button_data_action [String] `data-action` attribute for the close button
5
9
  # @param advance [Boolean] Whether to update the browser history when opening and closing the modal
6
10
  # @param header_divider [Boolean] Whether to show a divider between the header and the main content
7
11
  # @param footer_divider [Boolean] Whether to show a divider between the main content and the footer
@@ -10,6 +14,8 @@ class UltimateTurboModal::Base < Phlex::HTML
10
14
  def initialize(
11
15
  padding: UltimateTurboModal.configuration.padding,
12
16
  close_button: UltimateTurboModal.configuration.close_button,
17
+ close_button_sr_label: "Close modal",
18
+ close_button_data_action: "modal#hideModal",
13
19
  advance: UltimateTurboModal.configuration.advance,
14
20
  header: UltimateTurboModal.configuration.header,
15
21
  header_divider: UltimateTurboModal.configuration.header_divider,
@@ -18,6 +24,8 @@ class UltimateTurboModal::Base < Phlex::HTML
18
24
  )
19
25
  @padding = padding
20
26
  @close_button = close_button
27
+ @close_button_sr_label = close_button_sr_label
28
+ @close_button_data_action = close_button_data_action
21
29
  @advance = !!advance
22
30
  @advance_url = advance if advance.present? && advance.is_a?(String)
23
31
  @title = title
@@ -93,4 +101,124 @@ class UltimateTurboModal::Base < Phlex::HTML
93
101
  def respond_to_missing?(method, include_private = false)
94
102
  self.class.included_modules.any? { |mod| mod.instance_methods.include?(method) } || super
95
103
  end
104
+
105
+ ## HTML components
106
+
107
+ def modal(&)
108
+ outer_divs do
109
+ div_content do
110
+ div_header
111
+ div_main(&)
112
+ div_footer if footer?
113
+ end
114
+ end
115
+ end
116
+
117
+ def outer_divs(&)
118
+ div_dialog do
119
+ div_overlay
120
+ div_outer do
121
+ div_inner(&)
122
+ end
123
+ end
124
+ end
125
+
126
+ def div_dialog(&)
127
+ div(id: "modal-container",
128
+ class: self.class::DIV_DIALOG_CLASSES,
129
+ role: "dialog",
130
+ aria: {
131
+ labeled_by: "modal-title-h",
132
+ modal: true
133
+ },
134
+ data: {
135
+ controller: "modal",
136
+ modal_target: "container",
137
+ modal_advance_url_value: advance_url,
138
+ action: "turbo:submit-end->modal#submitEnd keyup@window->modal#closeWithKeyboard click@window->modal#outsideModalClicked click->modal#outsideModalClicked",
139
+ transition_enter: "ease-out duration-100",
140
+ transition_enter_start: "opacity-0",
141
+ transition_enter_end: "opacity-100",
142
+ transition_leave: "ease-in duration-50",
143
+ transition_leave_start: "opacity-100",
144
+ transition_leave_end: "opacity-0",
145
+ padding: padding?.to_s,
146
+ title: title?.to_s,
147
+ header: header?.to_s,
148
+ close_button: close_button?.to_s,
149
+ header_divider: header_divider?.to_s,
150
+ footer_divider: footer_divider?.to_s
151
+ }, &)
152
+ end
153
+
154
+ def div_overlay
155
+ div(id: "modal-overlay", class: self.class::DIV_OVERLAY_CLASSES)
156
+ end
157
+
158
+ def div_outer(&)
159
+ div(id: "modal-outer", class: self.class::DIV_OUTER_CLASSES, &)
160
+ end
161
+
162
+ def div_inner(&)
163
+ div(id: "modal-inner", class: self.class::DIV_INNER_CLASSES, &)
164
+ end
165
+
166
+ def div_content(&)
167
+ div(id: "modal-content", class: self.class::DIV_CONTENT_CLASSES, data: {modal_target: "content"}, &)
168
+ end
169
+
170
+ def div_main(&)
171
+ div(id: "modal-main", class: self.class::DIV_MAIN_CLASSES, &)
172
+ end
173
+
174
+ def div_header(&)
175
+ div(id: "modal-header", class: self.class::DIV_HEADER_CLASSES) do
176
+ div_title
177
+ button_close
178
+ end
179
+ end
180
+
181
+ def div_title
182
+ div(id: "modal-title", class: self.class::DIV_TITLE_CLASSES) do
183
+ if @title_block.present?
184
+ render @title_block
185
+ else
186
+ h3(id: "modal-title-h", class: self.class::DIV_TITLE_H_CLASSES) { @title }
187
+ end
188
+ end
189
+ end
190
+
191
+ def div_footer
192
+ div(id: "modal-footer", class: self.class::DIV_FOOTER_CLASSES) do
193
+ render @footer
194
+ end
195
+ end
196
+
197
+ def button_close
198
+ div(id: "modal-close", class: self.class::BUTTON_CLOSE_CLASSES) do
199
+ close_button_tag do
200
+ icon_close
201
+ span(class: self.class::BUTTON_CLOSE_SR_ONLY_CLASSES) { @close_button_sr_label }
202
+ end
203
+ end
204
+ end
205
+
206
+ def close_button_tag(&)
207
+ button(type: "button",
208
+ aria: {label: "close"},
209
+ class: self.class::CLOSE_BUTTON_TAG_CLASSES,
210
+ data: {
211
+ action: @close_button_data_action
212
+ }, &)
213
+ end
214
+
215
+ def icon_close
216
+ svg(class: self.class::ICON_CLOSE_CLASSES, fill: "currentColor", viewBox: "0 0 20 20") do |s|
217
+ s.path(
218
+ fill_rule: "evenodd",
219
+ d: "M4.293 4.293a1 1 0 011.414 0L10 8.586l4.293-4.293a1 1 0 111.414 1.414L11.414 10l4.293 4.293a1 1 0 01-1.414 1.414L10 11.414l-4.293 4.293a1 1 0 01-1.414-1.414L8.586 10 4.293 5.707a1 1 0 010-1.414z",
220
+ clip_rule: "evenodd"
221
+ )
222
+ end
223
+ end
96
224
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module UltimateTurboModal
2
4
  class << self
3
5
  attr_accessor :configuration
@@ -1,137 +1,20 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module UltimateTurboModal::Flavors
2
4
  class Tailwind < UltimateTurboModal::Base
3
-
4
- private
5
-
6
- def modal(&)
7
- outer_divs do
8
- div_content do
9
- div_header
10
- div_main(&)
11
- div_footer if footer?
12
- end
13
- end
14
- end
15
-
16
- def outer_divs(&)
17
- div_dialog do
18
- div_overlay
19
- div_outer do
20
- div_inner(&)
21
- end
22
- end
23
- end
24
-
25
- def div_dialog(&)
26
- div(id: "modal-container",
27
- class: "relative group",
28
- role: "dialog",
29
- aria: {
30
- labeled_by: "modal-title-h",
31
- modal: true
32
- },
33
- data: {
34
- controller: "modal",
35
- modal_target: "container",
36
- modal_advance_url_value: advance_url,
37
- action: "turbo:submit-end->modal#submitEnd keyup@window->modal#closeWithKeyboard click@window->modal#outsideModalClicked click->modal#outsideModalClicked",
38
- transition_enter: "ease-out duration-100",
39
- transition_enter_start: "opacity-0",
40
- transition_enter_end: "opacity-100",
41
- transition_leave: "ease-in duration-50",
42
- transition_leave_start: "opacity-100",
43
- transition_leave_end: "opacity-0",
44
- padding: padding?.to_s,
45
- title: title?.to_s,
46
- header: header?.to_s,
47
- close_button: close_button?.to_s,
48
- header_divider: header_divider?.to_s,
49
- footer_divider: footer_divider?.to_s
50
- }, &)
51
- end
52
-
53
- def div_overlay
54
- div(id: "modal-overlay",
55
- class: "fixed inset-0 bg-gray-900 bg-opacity-50 transition-opacity dark:bg-opacity-80 z-40")
56
- end
57
-
58
- def div_outer(&)
59
- div(id: "modal-outer",
60
- class: "fixed inset-0 z-50 overflow-y-auto sm:max-w-[80%] md:max-w-3xl sm:mx-auto m-4", &)
61
- end
62
-
63
- def div_inner(&)
64
- div(id: "modal-inner",
65
- class: "flex min-h-full items-center justify-center p-1 sm:p-4", &)
66
- end
67
-
68
- def div_content(&)
69
- div(id: "modal-content",
70
- class: "relative transform overflow-hidden rounded-lg bg-white text-left shadow transition-all
71
- sm:my-8 sm:max-w-3xl dark:bg-gray-800 dark:text-white",
72
- data: {modal_target: "content"}, &)
73
- end
74
-
75
- def div_main(&)
76
- div(id: "modal-main", class: "group-data-[padding=true]:p-4 group-data-[padding=true]:pt-2", &)
77
- end
78
-
79
- def header_block
80
- return if @header_block.blank?
81
- render @header_block
82
- nil
83
- end
84
-
85
- def div_header(&)
86
- div(id: "modal-header", class: "flex justify-between items-center w-full py-4 rounded-t dark:border-gray-600 group-data-[header-divider=true]:border-b group-data-[header=false]:absolute") do
87
- div_title
88
- button_close
89
- end
90
- end
91
-
92
- def div_title
93
- div(id: "modal-title", class: "pl-4") do
94
- if @title_block.present?
95
- render @title_block
96
- else
97
- h3(id: "modal-title-h", class: "group-data-[title=false]:hidden text-lg font-semibold text-gray-900 dark:text-white") { @title }
98
- end
99
- end
100
- end
101
-
102
- def div_footer
103
- div(id: "modal-footer", class: "flex p-4 rounded-b dark:border-gray-600 group-data-[footer-divider=true]:border-t") do
104
- render @footer
105
- end
106
- end
107
-
108
- def button_close
109
- div(id: "modal-close", class: "mr-4 group-data-[close-button=false]:hidden") do
110
- close_button_tag do
111
- icon_close
112
- span(class: "sr-only") { "Close modal" }
113
- end
114
- end
115
- end
116
-
117
- def close_button_tag(&)
118
- button(type: "button",
119
- aria: {label: "close"},
120
- class: "text-gray-400 bg-transparent hover:bg-gray-200 hover:text-gray-900 rounded-lg text-sm
121
- p-1.5 ml-auto inline-flex items-center dark:hover:bg-gray-600 dark:hover:text-white",
122
- data: {
123
- action: "modal#hideModal"
124
- }, &)
125
- end
126
-
127
- def icon_close
128
- svg(class: "w-5 h-5", fill: "currentColor", viewBox: "0 0 20 20") do |s|
129
- s.path(
130
- fill_rule: "evenodd",
131
- d: "M4.293 4.293a1 1 0 011.414 0L10 8.586l4.293-4.293a1 1 0 111.414 1.414L11.414 10l4.293 4.293a1 1 0 01-1.414 1.414L10 11.414l-4.293 4.293a1 1 0 01-1.414-1.414L8.586 10 4.293 5.707a1 1 0 010-1.414z",
132
- clip_rule: "evenodd"
133
- )
134
- end
135
- end
5
+ DIV_DIALOG_CLASSES = "relative group"
6
+ DIV_OVERLAY_CLASSES = "fixed inset-0 bg-gray-900 bg-opacity-50 transition-opacity dark:bg-opacity-80 z-40"
7
+ DIV_OUTER_CLASSES = "fixed inset-0 z-50 overflow-y-auto sm:max-w-[80%] md:max-w-3xl sm:mx-auto m-4"
8
+ DIV_INNER_CLASSES = "flex min-h-full items-center justify-center p-1 sm:p-4"
9
+ DIV_CONTENT_CLASSES = "relative transform overflow-hidden rounded-lg bg-white text-left shadow transition-all sm:my-8 sm:max-w-3xl dark:bg-gray-800 dark:text-white"
10
+ DIV_MAIN_CLASSES = "group-data-[padding=true]:p-4 group-data-[padding=true]:pt-2"
11
+ DIV_HEADER_CLASSES = "flex justify-between items-center w-full py-4 rounded-t dark:border-gray-600 group-data-[header-divider=true]:border-b group-data-[header=false]:absolute"
12
+ DIV_TITLE_CLASSES = "pl-4"
13
+ DIV_TITLE_H_CLASSES = "group-data-[title=false]:hidden text-lg font-semibold text-gray-900 dark:text-white"
14
+ DIV_FOOTER_CLASSES = "flex p-4 rounded-b dark:border-gray-600 group-data-[footer-divider=true]:border-t"
15
+ BUTTON_CLOSE_CLASSES = "mr-4 group-data-[close-button=false]:hidden"
16
+ BUTTON_CLOSE_SR_ONLY_CLASSES = "sr-only"
17
+ CLOSE_BUTTON_TAG_CLASSES = "text-gray-400 bg-transparent hover:bg-gray-200 hover:text-gray-900 rounded-lg text-sm p-1.5 ml-auto inline-flex items-center dark:hover:bg-gray-600 dark:hover:text-white"
18
+ ICON_CLOSE_CLASSES = "w-5 h-5"
136
19
  end
137
20
  end
@@ -1,124 +1,20 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module UltimateTurboModal::Flavors
2
4
  class Vanilla < UltimateTurboModal::Base
3
-
4
- private
5
-
6
- def modal(&)
7
- outer_divs do
8
- div_content do
9
- div_header
10
- div_main(&)
11
- div_footer if footer?
12
- end
13
- end
14
- end
15
-
16
- def outer_divs(&)
17
- div_dialog do
18
- div_overlay
19
- div_outer do
20
- div_inner(&)
21
- end
22
- end
23
- end
24
-
25
- def div_dialog(&)
26
- div(id: "modal-container",
27
- class: "modal-container",
28
- role: "dialog",
29
- aria: {
30
- labeled_by: "modal-title-h",
31
- modal: true
32
- },
33
- data: {
34
- controller: "modal",
35
- modal_target: "container",
36
- modal_advance_url_value: advance_url,
37
- action: "turbo:submit-end->modal#submitEnd keyup@window->modal#closeWithKeyboard click@window->modal#outsideModalClicked click->modal#outsideModalClicked",
38
- transition_enter: "ease-out duration-100",
39
- transition_enter_start: "opacity-0",
40
- transition_enter_end: "opacity-100",
41
- transition_leave: "ease-in duration-50",
42
- transition_leave_start: "opacity-100",
43
- transition_leave_end: "opacity-0",
44
- padding: padding?.to_s,
45
- title: title?.to_s,
46
- header: header?.to_s,
47
- close_button: close_button?.to_s,
48
- header_divider: header_divider?.to_s,
49
- footer_divider: footer_divider?.to_s
50
- }, &)
51
- end
52
-
53
- def div_overlay
54
- div(id: "modal-overlay", class: "modal-overlay")
55
- end
56
-
57
- def div_outer(&)
58
- div(id: "modal-outer", class: "modal-outer", &)
59
- end
60
-
61
- def div_inner(&)
62
- div(id: "modal-inner", class: "modal-inner", &)
63
- end
64
-
65
- def div_content(&)
66
- div(id: "modal-content", class: "modal-content", data: {modal_target: "content"}, &)
67
- end
68
-
69
- def div_main(&)
70
- div(id: "modal-main", class: "modal-main", &)
71
- end
72
-
73
- def div_header(&)
74
- div(id: "modal-header", class: "modal-header") do
75
- div_title
76
- button_close
77
- end
78
- end
79
-
80
- def div_title
81
- div(id: "modal-title", class: "modal-title") do
82
- if @title_block.present?
83
- render @title_block
84
- else
85
- h3(id: "modal-title-h", class: "modal-title-h") { @title }
86
- end
87
- end
88
- end
89
-
90
- def div_footer
91
- div(id: "modal-footer", class: "modal-footer") do
92
- render @footer
93
- end
94
- end
95
-
96
- def button_close
97
- div(id: "modal-close", class: "modal-close") do
98
- close_button_tag do
99
- icon_close
100
- span(class: "sr-only") { "Close modal" }
101
- end
102
- end
103
- end
104
-
105
- def close_button_tag(&)
106
- button(type: "button",
107
- aria: {label: "close"},
108
- class: "modal-close-button",
109
- data: {
110
- action: "modal#hideModal"
111
- }, &)
112
- end
113
-
114
- def icon_close
115
- svg(class: "modal-close-icon", fill: "currentColor", viewBox: "0 0 20 20") do |s|
116
- s.path(
117
- fill_rule: "evenodd",
118
- d: "M4.293 4.293a1 1 0 011.414 0L10 8.586l4.293-4.293a1 1 0 111.414 1.414L11.414 10l4.293 4.293a1 1 0 01-1.414 1.414L10 11.414l-4.293 4.293a1 1 0 01-1.414-1.414L8.586 10 4.293 5.707a1 1 0 010-1.414z",
119
- clip_rule: "evenodd"
120
- )
121
- end
122
- end
5
+ DIV_DIALOG_CLASSES = "modal-container"
6
+ DIV_OVERLAY_CLASSES = "modal-overlay"
7
+ DIV_OUTER_CLASSES = "modal-outer"
8
+ DIV_INNER_CLASSES = "modal-inner"
9
+ DIV_CONTENT_CLASSES = "modal-content"
10
+ DIV_MAIN_CLASSES = "modal-main"
11
+ DIV_HEADER_CLASSES = "modal-header"
12
+ DIV_TITLE_CLASSES = "modal-title"
13
+ DIV_TITLE_H_CLASSES = "modal-title-h"
14
+ DIV_FOOTER_CLASSES = "modal-footer"
15
+ BUTTON_CLOSE_CLASSES = "modal-close"
16
+ BUTTON_CLOSE_SR_ONLY_CLASSES = "sr-only"
17
+ CLOSE_BUTTON_TAG_CLASSES = "modal-close-button"
18
+ ICON_CLOSE_CLASSES = "modal-close-icon"
123
19
  end
124
20
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module UltimateTurboModal::Helpers
2
4
  module ControllerHelper
3
5
  extend ActiveSupport::Concern
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module UltimateTurboModal::Helpers
2
4
  module StreamHelper
3
5
  def modal(message)
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module UltimateTurboModal::Helpers
2
4
  module ViewHelper
3
5
  def modal(**, &)
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module UltimateTurboModal
4
- VERSION = "1.3.1"
4
+ VERSION = "1.4.0"
5
5
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ultimate_turbo_modal
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.3.1
4
+ version: 1.4.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Carl Mercier
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2023-11-23 00:00:00.000000000 Z
11
+ date: 2023-11-24 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: phlex-rails