ultimate_turbo_modal 2.1.2 → 2.2.2
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/.tool-versions +1 -1
- data/CHANGELOG.md +17 -0
- data/CLAUDE.md +188 -2
- data/Gemfile.lock +1 -1
- data/README.md +22 -0
- data/VERSION +1 -1
- data/javascript/index.js +12 -3
- data/javascript/modal_controller.js +16 -4
- data/javascript/package.json +2 -1
- data/javascript/styles/vanilla.css +86 -0
- data/lib/generators/ultimate_turbo_modal/base.rb +117 -0
- data/lib/generators/ultimate_turbo_modal/install_generator.rb +46 -95
- data/lib/generators/ultimate_turbo_modal/templates/flavors/custom.rb +29 -2
- data/lib/generators/ultimate_turbo_modal/templates/flavors/tailwind.rb +30 -3
- data/lib/generators/ultimate_turbo_modal/templates/flavors/tailwind3.rb +29 -2
- data/lib/generators/ultimate_turbo_modal/templates/flavors/vanilla.rb +31 -3
- data/lib/generators/ultimate_turbo_modal/update_generator.rb +109 -0
- data/lib/ultimate_turbo_modal/base.rb +35 -14
- data/lib/ultimate_turbo_modal.rb +2 -0
- data/script/build_and_release.sh +20 -7
- metadata +8 -99
- data/demo-app/.gitattributes +0 -7
- data/demo-app/.gitignore +0 -34
- data/demo-app/.ruby-version +0 -1
- data/demo-app/.tool-versions +0 -2
- data/demo-app/Gemfile +0 -41
- data/demo-app/Gemfile.lock +0 -248
- data/demo-app/Procfile.dev +0 -3
- data/demo-app/README.md +0 -15
- data/demo-app/Rakefile +0 -6
- data/demo-app/app/assets/builds/.keep +0 -0
- data/demo-app/app/assets/images/.keep +0 -0
- data/demo-app/app/assets/stylesheets/application.css +0 -42
- data/demo-app/app/controllers/application_controller.rb +0 -10
- data/demo-app/app/controllers/concerns/.keep +0 -0
- data/demo-app/app/controllers/concerns/set_flavor.rb +0 -10
- data/demo-app/app/controllers/hide_from_backends_controller.rb +0 -34
- data/demo-app/app/controllers/modal_controller.rb +0 -11
- data/demo-app/app/controllers/posts_controller.rb +0 -69
- data/demo-app/app/controllers/welcome_controller.rb +0 -2
- data/demo-app/app/helpers/application_helper.rb +0 -9
- data/demo-app/app/javascript/application.js +0 -4
- data/demo-app/app/javascript/controllers/application.js +0 -13
- data/demo-app/app/javascript/controllers/dark_mode_controller.js +0 -28
- data/demo-app/app/javascript/controllers/flash_controller.js +0 -9
- data/demo-app/app/javascript/controllers/hello_controller.js +0 -7
- data/demo-app/app/javascript/controllers/index.js +0 -15
- data/demo-app/app/models/application_record.rb +0 -3
- data/demo-app/app/models/concerns/.keep +0 -0
- data/demo-app/app/models/post.rb +0 -4
- data/demo-app/app/views/hide_from_backends/_notice.html.erb +0 -10
- data/demo-app/app/views/hide_from_backends/create.turbo_stream.erb +0 -2
- data/demo-app/app/views/hide_from_backends/new.html.erb +0 -30
- data/demo-app/app/views/layouts/application.html.erb +0 -40
- data/demo-app/app/views/modal/index.html.erb +0 -45
- data/demo-app/app/views/modal/show.html.erb +0 -39
- data/demo-app/app/views/posts/_form.html.erb +0 -36
- data/demo-app/app/views/posts/_post.html.erb +0 -9
- data/demo-app/app/views/posts/edit.html.erb +0 -9
- data/demo-app/app/views/posts/index.html.erb +0 -14
- data/demo-app/app/views/posts/new.html.erb +0 -3
- data/demo-app/app/views/posts/show.html.erb +0 -21
- data/demo-app/app/views/shared/_flash.html.erb +0 -13
- data/demo-app/app/views/welcome/index.html.erb +0 -19
- data/demo-app/bin/bundle +0 -109
- data/demo-app/bin/dev +0 -18
- data/demo-app/bin/rails +0 -4
- data/demo-app/bin/rake +0 -4
- data/demo-app/bin/setup +0 -34
- data/demo-app/config/application.rb +0 -43
- data/demo-app/config/boot.rb +0 -3
- data/demo-app/config/credentials.yml.enc +0 -1
- data/demo-app/config/database.yml +0 -25
- data/demo-app/config/environment.rb +0 -14
- data/demo-app/config/environments/development.rb +0 -51
- data/demo-app/config/environments/production.rb +0 -67
- data/demo-app/config/environments/test.rb +0 -42
- data/demo-app/config/initializers/assets.rb +0 -7
- data/demo-app/config/initializers/content_security_policy.rb +0 -25
- data/demo-app/config/initializers/filter_parameter_logging.rb +0 -8
- data/demo-app/config/initializers/inflections.rb +0 -14
- data/demo-app/config/initializers/new_framework_defaults_8_0.rb +0 -30
- data/demo-app/config/initializers/permissions_policy.rb +0 -11
- data/demo-app/config/initializers/ultimate_turbo_modal.rb +0 -12
- data/demo-app/config/initializers/ultimate_turbo_modal_tailwind.rb +0 -21
- data/demo-app/config/initializers/ultimate_turbo_modal_vanilla.rb +0 -21
- data/demo-app/config/locales/en.yml +0 -33
- data/demo-app/config/puma.rb +0 -41
- data/demo-app/config/routes.rb +0 -9
- data/demo-app/config.ru +0 -6
- data/demo-app/db/migrate/20230331002502_create_posts.rb +0 -10
- data/demo-app/db/migrate/20231031012703_add_post.rb +0 -9
- data/demo-app/db/migrate/20231128141054_add_publish_on_to_posts.rb +0 -5
- data/demo-app/db/schema.rb +0 -22
- data/demo-app/lib/assets/.keep +0 -0
- data/demo-app/lib/tasks/.keep +0 -0
- data/demo-app/log/.keep +0 -0
- data/demo-app/package.json +0 -28
- data/demo-app/postcss.config.js +0 -7
- data/demo-app/public/400.html +0 -114
- data/demo-app/public/404.html +0 -114
- data/demo-app/public/406-unsupported-browser.html +0 -114
- data/demo-app/public/422.html +0 -114
- data/demo-app/public/500.html +0 -114
- data/demo-app/public/apple-touch-icon-precomposed.png +0 -0
- data/demo-app/public/apple-touch-icon.png +0 -0
- data/demo-app/public/favicon.ico +0 -0
- data/demo-app/public/icon.png +0 -0
- data/demo-app/public/icon.svg +0 -3
- data/demo-app/public/img/bootstrap-logo-shadow.png +0 -0
- data/demo-app/public/img/unicat.jpg +0 -0
- data/demo-app/public/img/vanilla.png +0 -0
- data/demo-app/public/robots.txt +0 -1
- data/demo-app/tmp/.keep +0 -0
- data/demo-app/tmp/pids/.keep +0 -0
- data/demo-app/vendor/.keep +0 -0
- data/demo-app/yarn.lock +0 -1035
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
require "rails/generators"
|
|
4
|
-
|
|
4
|
+
require_relative "base"
|
|
5
5
|
|
|
6
6
|
module UltimateTurboModal
|
|
7
7
|
module Generators
|
|
8
|
-
class InstallGenerator <
|
|
8
|
+
class InstallGenerator < UltimateTurboModal::Generators::Base
|
|
9
9
|
source_root File.expand_path("templates", __dir__)
|
|
10
10
|
|
|
11
11
|
desc "Installs UltimateTurboModal: copies initializer/flavor, sets up JS, registers Stimulus controller, adds Turbo Frame."
|
|
@@ -17,99 +17,61 @@ module UltimateTurboModal
|
|
|
17
17
|
|
|
18
18
|
# Step 2: Setup Javascript Dependencies (Yarn/npm/Bun or Importmap)
|
|
19
19
|
def setup_javascript_dependencies
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
say "\nAttempting to set up JavaScript dependencies...", :yellow
|
|
23
|
-
|
|
24
|
-
if uses_importmaps?
|
|
25
|
-
say "Detected Importmaps. Pinning #{package_name}...", :green
|
|
26
|
-
run "bin/importmap pin #{package_name}"
|
|
27
|
-
|
|
28
|
-
say "\n✅ Pinned '#{package_name}' via importmap.", :green
|
|
29
|
-
|
|
30
|
-
elsif uses_javascript_bundler?
|
|
31
|
-
say "Detected jsbundling-rails (Yarn/npm/Bun). Adding #{package_name} package...", :green
|
|
32
|
-
if uses_yarn?
|
|
33
|
-
run "yarn add #{package_name}"
|
|
34
|
-
say "\n✅ Added '#{package_name}' using Yarn.", :green
|
|
35
|
-
elsif uses_npm?
|
|
36
|
-
run "npm install --save #{package_name}"
|
|
37
|
-
say "\n✅ Added '#{package_name}' using npm.", :green
|
|
38
|
-
elsif uses_bun?
|
|
39
|
-
run "bun add #{package_name}"
|
|
40
|
-
say "\n✅ Added '#{package_name}' using Bun.", :green
|
|
41
|
-
else
|
|
42
|
-
# Default or fallback: Try yarn, but provide instructions for others
|
|
43
|
-
say "Attempting to add with Yarn. If you use npm or Bun, please add manually.", :yellow
|
|
44
|
-
run "yarn add #{package_name}"
|
|
45
|
-
say "\n✅ Attempted to add '#{package_name}' using Yarn.", :green
|
|
46
|
-
say " If this failed or you use npm/bun, please run:", :yellow
|
|
47
|
-
say " npm install --save #{package_name}", :cyan
|
|
48
|
-
say " # or", :cyan
|
|
49
|
-
say " bun add #{package_name}\n", :cyan
|
|
50
|
-
end
|
|
51
|
-
else
|
|
52
|
-
# Fallback instructions if neither is clearly detected
|
|
53
|
-
say "\nCould not automatically detect Importmaps or jsbundling-rails.", :yellow
|
|
54
|
-
say "Please manually add the '#{package_name}' JavaScript package.", :yellow
|
|
55
|
-
say "If using Importmaps: bin/importmap pin #{package_name}", :cyan
|
|
56
|
-
say "If using Yarn: yarn add #{package_name}", :cyan
|
|
57
|
-
say "If using npm: npm install --save #{package_name}", :cyan
|
|
58
|
-
say "If using Bun: bun add #{package_name}", :cyan
|
|
59
|
-
say "Then, import it in your app/javascript/application.js:", :yellow
|
|
60
|
-
say "import '#{package_name}'\n", :cyan
|
|
61
|
-
end
|
|
20
|
+
add_js_dependency
|
|
62
21
|
end
|
|
63
22
|
|
|
64
23
|
# Step 3: Register Stimulus Controller
|
|
65
24
|
def setup_stimulus_controller
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
controller_name = "UltimateTurboModalController"
|
|
69
|
-
stimulus_identifier = "modal"
|
|
25
|
+
index_path = rails_root_join("app", "javascript", "controllers", "index.js")
|
|
26
|
+
application_path = rails_root_join("app", "javascript", "controllers", "application.js")
|
|
27
|
+
controller_name = "UltimateTurboModalController"
|
|
28
|
+
stimulus_identifier = "modal"
|
|
70
29
|
|
|
71
|
-
import_line = "import { #{controller_name} } from \"#{
|
|
30
|
+
import_line = "import { #{controller_name} } from \"#{package_name}\"\n"
|
|
72
31
|
register_line = "application.register(\"#{stimulus_identifier}\", #{controller_name})\n"
|
|
73
32
|
|
|
74
|
-
|
|
33
|
+
# Determine which file contains Application.start() — it may be index.js or application.js
|
|
34
|
+
target_path, file_content = find_stimulus_target(index_path, application_path)
|
|
35
|
+
|
|
36
|
+
say "\nAttempting to register Stimulus controller...", :yellow
|
|
75
37
|
|
|
76
|
-
unless
|
|
77
|
-
say "❌ Stimulus controllers
|
|
38
|
+
unless target_path
|
|
39
|
+
say "❌ Stimulus controllers file not found.", :red
|
|
78
40
|
say " Please manually add the following lines to your Stimulus setup:", :yellow
|
|
79
41
|
say " #{import_line.strip}", :cyan
|
|
80
42
|
say " #{register_line.strip}\n", :cyan
|
|
81
|
-
return
|
|
43
|
+
return
|
|
82
44
|
end
|
|
83
45
|
|
|
84
|
-
|
|
85
|
-
file_content = File.read(stimulus_controller_path)
|
|
46
|
+
say " Target file: #{target_path}", :yellow
|
|
86
47
|
|
|
87
|
-
# Insert the import statement after
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
48
|
+
# Insert the import statement after an existing import from @hotwired/stimulus or ./application
|
|
49
|
+
import_anchor = /import .* from ["'](?:@hotwired\/stimulus|\.\/application)["']\n/
|
|
50
|
+
if file_content.include?(import_line)
|
|
51
|
+
say "⏩ Import statement already exists.", :blue
|
|
52
|
+
elsif file_content.match?(import_anchor)
|
|
53
|
+
insert_into_file target_path, import_line, after: import_anchor
|
|
92
54
|
say "✅ Added import statement.", :green
|
|
93
|
-
elsif
|
|
94
|
-
|
|
95
|
-
insert_into_file stimulus_controller_path, import_line, before: /import/
|
|
55
|
+
elsif file_content.match?(/import/)
|
|
56
|
+
insert_into_file target_path, import_line, before: /import/
|
|
96
57
|
say "✅ Added import statement (fallback position).", :green
|
|
97
58
|
else
|
|
98
|
-
|
|
59
|
+
prepend_to_file target_path, import_line
|
|
60
|
+
say "✅ Added import statement (prepended to file).", :green
|
|
99
61
|
end
|
|
100
62
|
|
|
101
|
-
|
|
102
63
|
# Insert the register statement after Application.start()
|
|
103
|
-
register_anchor = /Application\.start
|
|
104
|
-
if file_content.
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
say "
|
|
109
|
-
say " Please manually add this line after your Stimulus application starts:", :yellow
|
|
110
|
-
say " #{register_line.strip}\n", :cyan
|
|
64
|
+
register_anchor = /Application\.start\(\)\n/
|
|
65
|
+
if file_content.include?(register_line)
|
|
66
|
+
say "⏩ Controller registration already exists.", :blue
|
|
67
|
+
elsif file_content.match?(register_anchor)
|
|
68
|
+
insert_into_file target_path, register_line, after: register_anchor
|
|
69
|
+
say "✅ Added controller registration.", :green
|
|
111
70
|
else
|
|
112
|
-
|
|
71
|
+
say "❌ Could not find `Application.start()` line in #{target_path}.", :red
|
|
72
|
+
say " Please manually add these lines to your Stimulus setup:", :yellow
|
|
73
|
+
say " #{import_line.strip}", :cyan
|
|
74
|
+
say " #{register_line.strip}\n", :cyan
|
|
113
75
|
end
|
|
114
76
|
end
|
|
115
77
|
|
|
@@ -196,28 +158,17 @@ module UltimateTurboModal
|
|
|
196
158
|
end
|
|
197
159
|
end
|
|
198
160
|
|
|
199
|
-
def
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
end
|
|
206
|
-
|
|
207
|
-
def uses_yarn?
|
|
208
|
-
File.exist?(rails_root_join("yarn.lock"))
|
|
209
|
-
end
|
|
210
|
-
|
|
211
|
-
def uses_npm?
|
|
212
|
-
File.exist?(rails_root_join("package-lock.json")) && !uses_yarn? && !uses_bun?
|
|
213
|
-
end
|
|
214
|
-
|
|
215
|
-
def uses_bun?
|
|
216
|
-
File.exist?(rails_root_join("bun.lockb"))
|
|
217
|
-
end
|
|
161
|
+
def find_stimulus_target(index_path, application_path)
|
|
162
|
+
[index_path, application_path].each do |path|
|
|
163
|
+
next unless File.exist?(path)
|
|
164
|
+
content = File.read(path)
|
|
165
|
+
return [path, content] if content.match?(/Application\.start\(\)/)
|
|
166
|
+
end
|
|
218
167
|
|
|
219
|
-
|
|
220
|
-
|
|
168
|
+
# Fall back to index.js even without Application.start()
|
|
169
|
+
if File.exist?(index_path)
|
|
170
|
+
[index_path, File.read(index_path)]
|
|
171
|
+
end
|
|
221
172
|
end
|
|
222
173
|
end
|
|
223
174
|
end
|
|
@@ -4,9 +4,9 @@
|
|
|
4
4
|
# TODO: define the classes for each HTML element.
|
|
5
5
|
module UltimateTurboModal::Flavors
|
|
6
6
|
class Custom < UltimateTurboModal::Base
|
|
7
|
-
|
|
7
|
+
DIV_MODAL_CONTAINER_CLASSES = ""
|
|
8
8
|
DIV_OVERLAY_CLASSES = ""
|
|
9
|
-
|
|
9
|
+
DIV_DIALOG_CLASSES = ""
|
|
10
10
|
DIV_INNER_CLASSES = ""
|
|
11
11
|
DIV_CONTENT_CLASSES = ""
|
|
12
12
|
DIV_MAIN_CLASSES = ""
|
|
@@ -18,5 +18,32 @@ module UltimateTurboModal::Flavors
|
|
|
18
18
|
BUTTON_CLOSE_SR_ONLY_CLASSES = ""
|
|
19
19
|
CLOSE_BUTTON_TAG_CLASSES = ""
|
|
20
20
|
ICON_CLOSE_CLASSES = ""
|
|
21
|
+
|
|
22
|
+
TRANSITIONS = {
|
|
23
|
+
overlay: {
|
|
24
|
+
enter: {
|
|
25
|
+
animation: "",
|
|
26
|
+
start: "",
|
|
27
|
+
end: ""
|
|
28
|
+
},
|
|
29
|
+
leave: {
|
|
30
|
+
animation: "",
|
|
31
|
+
start: "",
|
|
32
|
+
end: ""
|
|
33
|
+
}
|
|
34
|
+
},
|
|
35
|
+
dialog: {
|
|
36
|
+
enter: {
|
|
37
|
+
animation: "",
|
|
38
|
+
start: "",
|
|
39
|
+
end: ""
|
|
40
|
+
},
|
|
41
|
+
leave: {
|
|
42
|
+
animation: "",
|
|
43
|
+
start: "",
|
|
44
|
+
end: ""
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
}
|
|
21
48
|
end
|
|
22
49
|
end
|
|
@@ -3,9 +3,9 @@
|
|
|
3
3
|
# Tailwind CSS v4
|
|
4
4
|
module UltimateTurboModal::Flavors
|
|
5
5
|
class Tailwind < UltimateTurboModal::Base
|
|
6
|
-
|
|
7
|
-
DIV_OVERLAY_CLASSES = "fixed inset-0 bg-gray-900/70 transition-opacity dark:bg-gray-900/80"
|
|
8
|
-
|
|
6
|
+
DIV_MODAL_CONTAINER_CLASSES = "relative group z-50"
|
|
7
|
+
DIV_OVERLAY_CLASSES = "fixed inset-0 bg-gray-900/70 transition-opacity dark:bg-gray-900/80 opacity-0"
|
|
8
|
+
DIV_DIALOG_CLASSES = "fixed inset-0 overflow-y-auto sm:max-w-[80%] md:max-w-3xl sm:mx-auto m-4 opacity-0"
|
|
9
9
|
DIV_INNER_CLASSES = "flex min-h-full items-start justify-center pt-[10vh] sm:p-4"
|
|
10
10
|
DIV_CONTENT_CLASSES = "relative transform max-h-screen overflow-hidden rounded-lg bg-white text-left shadow-lg transition-all sm:my-8 sm:max-w-3xl dark:bg-gray-800 dark:text-white"
|
|
11
11
|
DIV_MAIN_CLASSES = "group-data-[padding=true]:p-4 group-data-[padding=true]:pt-2 overflow-y-auto max-h-[75vh]"
|
|
@@ -17,5 +17,32 @@ module UltimateTurboModal::Flavors
|
|
|
17
17
|
BUTTON_CLOSE_SR_ONLY_CLASSES = "sr-only"
|
|
18
18
|
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"
|
|
19
19
|
ICON_CLOSE_CLASSES = "w-5 h-5"
|
|
20
|
+
|
|
21
|
+
TRANSITIONS = {
|
|
22
|
+
overlay: {
|
|
23
|
+
enter: {
|
|
24
|
+
animation: "ease-out duration-300",
|
|
25
|
+
start: "opacity-0",
|
|
26
|
+
end: "opacity-100"
|
|
27
|
+
},
|
|
28
|
+
leave: {
|
|
29
|
+
animation: "ease-in duration-200",
|
|
30
|
+
start: "opacity-100",
|
|
31
|
+
end: "opacity-0"
|
|
32
|
+
}
|
|
33
|
+
},
|
|
34
|
+
dialog: {
|
|
35
|
+
enter: {
|
|
36
|
+
animation: "ease-out duration-300",
|
|
37
|
+
start: "opacity-0 translate-y-4 sm:translate-y-0 sm:scale-95",
|
|
38
|
+
end: "opacity-100 translate-y-0 sm:scale-100"
|
|
39
|
+
},
|
|
40
|
+
leave: {
|
|
41
|
+
animation: "ease-in duration-200",
|
|
42
|
+
start: "opacity-100 translate-y-0 sm:scale-100",
|
|
43
|
+
end: "opacity-0 translate-y-4 sm:translate-y-0 sm:scale-95"
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
}
|
|
20
47
|
end
|
|
21
48
|
end
|
|
@@ -3,9 +3,9 @@
|
|
|
3
3
|
# Tailwind CSS v3
|
|
4
4
|
module UltimateTurboModal::Flavors
|
|
5
5
|
class Tailwind3 < UltimateTurboModal::Base
|
|
6
|
-
|
|
6
|
+
DIV_MODAL_CONTAINER_CLASSES = "relative z-50"
|
|
7
7
|
DIV_OVERLAY_CLASSES = "fixed inset-0 bg-gray-900 bg-opacity-70 transition-opacity dark:bg-gray-900 dark:bg-opacity-80"
|
|
8
|
-
|
|
8
|
+
DIV_DIALOG_CLASSES = "fixed inset-0 overflow-y-auto sm:max-w-[80%] md:max-w-3xl sm:mx-auto m-4"
|
|
9
9
|
DIV_INNER_CLASSES = "flex min-h-full items-start justify-center pt-[10vh] sm:p-4"
|
|
10
10
|
DIV_CONTENT_CLASSES = "relative transform max-h-screen overflow-hidden rounded-lg bg-white text-left shadow-xl transition-all sm:my-8 sm:max-w-3xl dark:bg-gray-800 dark:text-white"
|
|
11
11
|
DIV_MAIN_CLASSES = "p-4 pt-2 overflow-y-auto max-h-[75vh]"
|
|
@@ -17,5 +17,32 @@ module UltimateTurboModal::Flavors
|
|
|
17
17
|
BUTTON_CLOSE_SR_ONLY_CLASSES = "sr-only"
|
|
18
18
|
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"
|
|
19
19
|
ICON_CLOSE_CLASSES = "w-5 h-5"
|
|
20
|
+
|
|
21
|
+
TRANSITIONS = {
|
|
22
|
+
overlay: {
|
|
23
|
+
enter: {
|
|
24
|
+
animation: "ease-out duration-300",
|
|
25
|
+
start: "opacity-0",
|
|
26
|
+
end: "opacity-100"
|
|
27
|
+
},
|
|
28
|
+
leave: {
|
|
29
|
+
animation: "ease-in duration-200",
|
|
30
|
+
start: "opacity-100",
|
|
31
|
+
end: "opacity-0"
|
|
32
|
+
}
|
|
33
|
+
},
|
|
34
|
+
dialog: {
|
|
35
|
+
enter: {
|
|
36
|
+
animation: "ease-out duration-300",
|
|
37
|
+
start: "opacity-0 translate-y-4 sm:translate-y-0 sm:scale-95",
|
|
38
|
+
end: "opacity-100 translate-y-0 sm:scale-100"
|
|
39
|
+
},
|
|
40
|
+
leave: {
|
|
41
|
+
animation: "ease-in duration-200",
|
|
42
|
+
start: "opacity-100 translate-y-0 sm:scale-100",
|
|
43
|
+
end: "opacity-0 translate-y-4 sm:translate-y-0 sm:scale-95"
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
}
|
|
20
47
|
end
|
|
21
48
|
end
|
|
@@ -3,9 +3,10 @@
|
|
|
3
3
|
# Vanilla CSS
|
|
4
4
|
module UltimateTurboModal::Flavors
|
|
5
5
|
class Vanilla < UltimateTurboModal::Base
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
6
|
+
DIV_MODAL_CONTAINER_CLASSES = "modal-container"
|
|
7
|
+
# Include enter-start classes so initial paint is hidden and transitions can animate smoothly
|
|
8
|
+
DIV_OVERLAY_CLASSES = "modal-overlay modal-transition-overlay-enter-start"
|
|
9
|
+
DIV_DIALOG_CLASSES = "modal-outer modal-transition-dialog-enter-start"
|
|
9
10
|
DIV_INNER_CLASSES = "modal-inner"
|
|
10
11
|
DIV_CONTENT_CLASSES = "modal-content"
|
|
11
12
|
DIV_MAIN_CLASSES = "modal-main"
|
|
@@ -17,5 +18,32 @@ module UltimateTurboModal::Flavors
|
|
|
17
18
|
BUTTON_CLOSE_SR_ONLY_CLASSES = "sr-only"
|
|
18
19
|
CLOSE_BUTTON_TAG_CLASSES = "modal-close-button"
|
|
19
20
|
ICON_CLOSE_CLASSES = "modal-close-icon"
|
|
21
|
+
|
|
22
|
+
TRANSITIONS = {
|
|
23
|
+
overlay: {
|
|
24
|
+
enter: {
|
|
25
|
+
animation: "modal-transition-overlay-enter-animation",
|
|
26
|
+
start: "modal-transition-overlay-enter-start",
|
|
27
|
+
end: "modal-transition-overlay-enter-end"
|
|
28
|
+
},
|
|
29
|
+
leave: {
|
|
30
|
+
animation: "modal-transition-overlay-leave-animation",
|
|
31
|
+
start: "modal-transition-overlay-leave-start",
|
|
32
|
+
end: "modal-transition-overlay-leave-end"
|
|
33
|
+
}
|
|
34
|
+
},
|
|
35
|
+
dialog: {
|
|
36
|
+
enter: {
|
|
37
|
+
animation: "modal-transition-dialog-enter-animation",
|
|
38
|
+
start: "modal-transition-dialog-enter-start",
|
|
39
|
+
end: "modal-transition-dialog-enter-end"
|
|
40
|
+
},
|
|
41
|
+
leave: {
|
|
42
|
+
animation: "modal-transition-dialog-leave-animation",
|
|
43
|
+
start: "modal-transition-dialog-leave-start",
|
|
44
|
+
end: "modal-transition-dialog-leave-end"
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
}
|
|
20
48
|
end
|
|
21
49
|
end
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "rails/generators"
|
|
4
|
+
require "json"
|
|
5
|
+
require "pathname"
|
|
6
|
+
require_relative "base"
|
|
7
|
+
|
|
8
|
+
module UltimateTurboModal
|
|
9
|
+
module Generators
|
|
10
|
+
class UpdateGenerator < UltimateTurboModal::Generators::Base
|
|
11
|
+
source_root File.expand_path("templates", __dir__)
|
|
12
|
+
|
|
13
|
+
desc "Updates UltimateTurboModal: aligns npm package version to gem version and refreshes the configured flavor initializer."
|
|
14
|
+
|
|
15
|
+
def update_npm_package_version
|
|
16
|
+
package_json_path = rails_root_join("package.json")
|
|
17
|
+
|
|
18
|
+
unless File.exist?(package_json_path)
|
|
19
|
+
say "No package.json found. Skipping npm package version update.", :yellow
|
|
20
|
+
return
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
begin
|
|
24
|
+
json = JSON.parse(File.read(package_json_path))
|
|
25
|
+
rescue JSON::ParserError => e
|
|
26
|
+
say "Unable to parse package.json: #{e.message}", :red
|
|
27
|
+
return
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
package_name = "ultimate_turbo_modal"
|
|
31
|
+
new_version = UltimateTurboModal::VERSION.to_s
|
|
32
|
+
|
|
33
|
+
# Special case: demo app links to local JS package; never update its version
|
|
34
|
+
if json.dig("dependencies", package_name) == "link:../javascript" ||
|
|
35
|
+
json.dig("devDependencies", package_name) == "link:../javascript"
|
|
36
|
+
say "Detected local link for '#{package_name}' (link:../javascript). Skipping version update.", :blue
|
|
37
|
+
return
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
updated = false
|
|
41
|
+
|
|
42
|
+
%w[dependencies devDependencies].each do |section|
|
|
43
|
+
next unless json.key?(section) && json[section].is_a?(Hash)
|
|
44
|
+
|
|
45
|
+
if json[section].key?(package_name)
|
|
46
|
+
old = json[section][package_name]
|
|
47
|
+
json[section][package_name] = new_version
|
|
48
|
+
updated = true if old != new_version
|
|
49
|
+
end
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
if updated
|
|
53
|
+
File.write(package_json_path, JSON.pretty_generate(json) + "\n")
|
|
54
|
+
say "Updated #{package_name} version in package.json to #{new_version}.", :green
|
|
55
|
+
else
|
|
56
|
+
say "Did not find #{package_name} in package.json dependencies. Nothing to update.", :blue
|
|
57
|
+
end
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
def install_js_dependencies
|
|
61
|
+
install_all_js_dependencies
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
def copy_flavor_file
|
|
65
|
+
flavor = detect_flavor
|
|
66
|
+
unless flavor
|
|
67
|
+
say "Could not determine UTMR flavor. Skipping flavor file copy.", :yellow
|
|
68
|
+
return
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
template_rel = "flavors/#{flavor}.rb"
|
|
72
|
+
template_abs = File.join(self.class.source_root, template_rel)
|
|
73
|
+
|
|
74
|
+
unless File.exist?(template_abs)
|
|
75
|
+
say "Flavor template not found for '#{flavor}' at #{template_abs}.", :red
|
|
76
|
+
return
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
target_path = "config/initializers/ultimate_turbo_modal_#{flavor}.rb"
|
|
80
|
+
copy_file template_rel, target_path, force: true
|
|
81
|
+
say "Copied flavor initializer to #{target_path}.", :green
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
private
|
|
85
|
+
|
|
86
|
+
def detect_flavor
|
|
87
|
+
command = nil
|
|
88
|
+
if File.exist?(rails_root_join("bin", "rails"))
|
|
89
|
+
command = "#{rails_root_join("bin", "rails")} runner \"puts UltimateTurboModal.configuration.flavor\""
|
|
90
|
+
else
|
|
91
|
+
command = "bundle exec rails runner \"puts UltimateTurboModal.configuration.flavor\""
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
output = `#{command}`
|
|
95
|
+
flavor = output.to_s.strip
|
|
96
|
+
flavor.empty? ? nil : flavor
|
|
97
|
+
rescue StandardError => e
|
|
98
|
+
say "Error determining flavor via rails runner: #{e.message}", :red
|
|
99
|
+
nil
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
def rails_root_join(*args)
|
|
103
|
+
Pathname.new(destination_root).join(*args)
|
|
104
|
+
end
|
|
105
|
+
end
|
|
106
|
+
end
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
|
|
@@ -55,7 +55,7 @@ class UltimateTurboModal::Base < Phlex::HTML
|
|
|
55
55
|
modal(&block)
|
|
56
56
|
end
|
|
57
57
|
elsif turbo_stream?
|
|
58
|
-
|
|
58
|
+
turbo_stream_action_tag("update", target: "modal") do
|
|
59
59
|
modal(&block)
|
|
60
60
|
end
|
|
61
61
|
else
|
|
@@ -104,6 +104,15 @@ class UltimateTurboModal::Base < Phlex::HTML
|
|
|
104
104
|
@advance_url || request&.original_url
|
|
105
105
|
end
|
|
106
106
|
|
|
107
|
+
# Wraps yielded content in a Turbo Frame if the current request originated from a Turbo Frame
|
|
108
|
+
def maybe_turbo_frame(frame_id, &block)
|
|
109
|
+
if turbo_frame?
|
|
110
|
+
turbo_frame_tag(frame_id, &block)
|
|
111
|
+
else
|
|
112
|
+
yield
|
|
113
|
+
end
|
|
114
|
+
end
|
|
115
|
+
|
|
107
116
|
def respond_to_missing?(method, include_private = false)
|
|
108
117
|
self.class.included_modules.any? { |mod| mod.instance_methods.include?(method) } || super
|
|
109
118
|
end
|
|
@@ -131,7 +140,7 @@ class UltimateTurboModal::Base < Phlex::HTML
|
|
|
131
140
|
def outer_divs(&block)
|
|
132
141
|
div_dialog do
|
|
133
142
|
div_overlay
|
|
134
|
-
|
|
143
|
+
div_outer_dialog do
|
|
135
144
|
div_inner(&block)
|
|
136
145
|
end
|
|
137
146
|
end
|
|
@@ -144,12 +153,6 @@ class UltimateTurboModal::Base < Phlex::HTML
|
|
|
144
153
|
modal_advance_url_value: advance_url,
|
|
145
154
|
modal_allowed_click_outside_selector_value: allowed_click_outside_selector,
|
|
146
155
|
action: "turbo:submit-end->modal#submitEnd keyup@window->modal#closeWithKeyboard click@window->modal#outsideModalClicked click->modal#outsideModalClicked",
|
|
147
|
-
transition_enter: "ease-out duration-100",
|
|
148
|
-
transition_enter_start: "opacity-0",
|
|
149
|
-
transition_enter_end: "opacity-100",
|
|
150
|
-
transition_leave: "ease-in duration-50",
|
|
151
|
-
transition_leave_start: "opacity-100",
|
|
152
|
-
transition_leave_end: "opacity-0",
|
|
153
156
|
padding: padding?.to_s,
|
|
154
157
|
title: title?.to_s,
|
|
155
158
|
header: header?.to_s,
|
|
@@ -163,7 +166,7 @@ class UltimateTurboModal::Base < Phlex::HTML
|
|
|
163
166
|
end
|
|
164
167
|
|
|
165
168
|
div(id: "modal-container",
|
|
166
|
-
class: self.class::
|
|
169
|
+
class: self.class::DIV_MODAL_CONTAINER_CLASSES,
|
|
167
170
|
role: "dialog",
|
|
168
171
|
aria: {
|
|
169
172
|
modal: true,
|
|
@@ -173,20 +176,38 @@ class UltimateTurboModal::Base < Phlex::HTML
|
|
|
173
176
|
end
|
|
174
177
|
|
|
175
178
|
def div_overlay
|
|
176
|
-
div(id: "modal-overlay", class: self.class::DIV_OVERLAY_CLASSES
|
|
179
|
+
div(id: "modal-overlay", class: self.class::DIV_OVERLAY_CLASSES, data: {
|
|
180
|
+
modal_target: "overlay",
|
|
181
|
+
transition_enter: self.class::TRANSITIONS[:overlay][:enter][:animation],
|
|
182
|
+
transition_enter_start: self.class::TRANSITIONS[:overlay][:enter][:start],
|
|
183
|
+
transition_enter_end: self.class::TRANSITIONS[:overlay][:enter][:end],
|
|
184
|
+
transition_leave: self.class::TRANSITIONS[:overlay][:leave][:animation],
|
|
185
|
+
transition_leave_start: self.class::TRANSITIONS[:overlay][:leave][:start],
|
|
186
|
+
transition_leave_end: self.class::TRANSITIONS[:overlay][:leave][:end]
|
|
187
|
+
})
|
|
177
188
|
end
|
|
178
189
|
|
|
179
|
-
def
|
|
180
|
-
div(id: "modal-outer", class: self.class::
|
|
190
|
+
def div_outer_dialog(&block)
|
|
191
|
+
div(id: "modal-outer", class: self.class::DIV_DIALOG_CLASSES, data: {
|
|
192
|
+
modal_target: "outer",
|
|
193
|
+
transition_enter: self.class::TRANSITIONS[:dialog][:enter][:animation],
|
|
194
|
+
transition_enter_start: self.class::TRANSITIONS[:dialog][:enter][:start],
|
|
195
|
+
transition_enter_end: self.class::TRANSITIONS[:dialog][:enter][:end],
|
|
196
|
+
transition_leave: self.class::TRANSITIONS[:dialog][:leave][:animation],
|
|
197
|
+
transition_leave_start: self.class::TRANSITIONS[:dialog][:leave][:start],
|
|
198
|
+
transition_leave_end: self.class::TRANSITIONS[:dialog][:leave][:end]
|
|
199
|
+
}, &block)
|
|
181
200
|
end
|
|
182
201
|
|
|
183
202
|
def div_inner(&block)
|
|
184
|
-
|
|
203
|
+
maybe_turbo_frame("modal-inner") do
|
|
204
|
+
div(id: "modal-inner", class: self.class::DIV_INNER_CLASSES, data: content_div_data, &block)
|
|
205
|
+
end
|
|
185
206
|
end
|
|
186
207
|
|
|
187
208
|
def div_content(&block)
|
|
188
209
|
data = (content_div_data || {}).merge({modal_target: "content"})
|
|
189
|
-
div(id: "modal-content", class: self.class::DIV_CONTENT_CLASSES, data
|
|
210
|
+
div(id: "modal-content", class: self.class::DIV_CONTENT_CLASSES, data: data, &block)
|
|
190
211
|
end
|
|
191
212
|
|
|
192
213
|
def div_main(&block)
|
data/lib/ultimate_turbo_modal.rb
CHANGED
|
@@ -5,7 +5,9 @@ require "phlex/deferred_render_with_main_content"
|
|
|
5
5
|
require "ultimate_turbo_modal/configuration"
|
|
6
6
|
require "ultimate_turbo_modal/railtie"
|
|
7
7
|
require "ultimate_turbo_modal/base"
|
|
8
|
+
require "generators/ultimate_turbo_modal/base"
|
|
8
9
|
require "generators/ultimate_turbo_modal/install_generator"
|
|
10
|
+
require "generators/ultimate_turbo_modal/update_generator"
|
|
9
11
|
|
|
10
12
|
module UltimateTurboModal
|
|
11
13
|
extend self
|
data/script/build_and_release.sh
CHANGED
|
@@ -23,14 +23,28 @@ if [ "$1" != "--skip-gem" ]; then
|
|
|
23
23
|
echo "Building and releasing gem..."
|
|
24
24
|
bundle exec rake build
|
|
25
25
|
|
|
26
|
-
#
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
26
|
+
# Update demo app with latest gem and JavaScript
|
|
27
|
+
echo "Updating demo app with latest code..."
|
|
28
|
+
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
29
|
+
DEMO_APP_DIR="$SCRIPT_DIR/../demo-app"
|
|
30
|
+
|
|
31
|
+
# Build JavaScript package first
|
|
32
|
+
echo "Building ultimate_turbo_modal JavaScript package..."
|
|
33
|
+
(cd "$SCRIPT_DIR/../javascript" && yarn build)
|
|
34
|
+
|
|
35
|
+
# Update demo app dependencies
|
|
36
|
+
echo "Installing latest ultimate_turbo_modal in demo app..."
|
|
37
|
+
(cd "$DEMO_APP_DIR" && bundle install)
|
|
38
|
+
(cd "$DEMO_APP_DIR" && yarn install --force)
|
|
39
|
+
|
|
40
|
+
# Check if Gemfile.lock or demo-app files are git dirty
|
|
41
|
+
if ! git diff --quiet Gemfile.lock demo-app/Gemfile.lock demo-app/yarn.lock; then
|
|
42
|
+
echo "Lock files are dirty. Adding, committing, and pushing."
|
|
43
|
+
git add Gemfile.lock demo-app/Gemfile.lock demo-app/yarn.lock
|
|
44
|
+
git commit -m "Update lock files for demo app"
|
|
32
45
|
fi
|
|
33
46
|
|
|
47
|
+
bundle exec rake build
|
|
34
48
|
bundle exec rake release
|
|
35
49
|
else
|
|
36
50
|
echo "Skipping gem build and release..."
|
|
@@ -45,4 +59,3 @@ else
|
|
|
45
59
|
fi
|
|
46
60
|
|
|
47
61
|
echo "Done!"
|
|
48
|
-
|