jet_ui 0.2.7 → 0.2.8

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: fcadff31d7c347d620f7426051002b85a7cdc18f245bd642b6bd0dddfc9ddb84
4
- data.tar.gz: 22ee5fb1f26ca32f57db44cd42b644c333235e69900264fe0c5affad323ee01c
3
+ metadata.gz: 7d81819a27f5eda163c7f4dd9d8b12973ae46cc82932cd1f272b59f40e2bf55d
4
+ data.tar.gz: de6951399df6add4915be32c9d55f1cdc1a9b1be4e090039f4d055bed24f4987
5
5
  SHA512:
6
- metadata.gz: 1a1a6e09e5dd6779994e47f3723774eb13d574049e08ad6b8b91b99cc38c9dd8e50639b57ed7f2dda1f0ba7b74bcad4ee34531dbd9de1d52c18bd22dd9bcd8f4
7
- data.tar.gz: 957311b4ac04bbe71784cdef0b31981a552db18b52bc55221b5ef93a4afeebc9a8e19b7e04e9114082fb129b8ce7fbafcaa06fb9648112c9be17be5b3bc73d08
6
+ metadata.gz: 9259ec8446ed0c0c6d6f790ad00c27e9f24c93cd065a3d6bba7fe07a5068b079ea1e70de6e70b47d37a2e4ecf25c211bca85a3ec1c940d991215273710aba7f1
7
+ data.tar.gz: e2c5e84a989af0b3e935e4f39bb0cfa3c0653e235f5839fe23ee39736349b749cba938b20f3511ad620f09d65ceaff27e92638d5b3f8d1506cea6ab4e61649fc
data/CHANGELOG.md CHANGED
@@ -7,6 +7,16 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
7
7
 
8
8
  ## [Unreleased]
9
9
 
10
+ ## [0.2.8] - 2026-07-09
11
+
12
+ ### Added
13
+ - `@jetrockets/jet-ui` npm package for Vite/esbuild/Webpack users — import Stimulus controllers without vendoring
14
+ - `JsRuntime` module for auto-detecting JS bundler (Vite, esbuild, Webpack) vs importmap
15
+ - `jet_ui:install` generator now detects runtime and prints runtime-specific setup instructions
16
+
17
+ ### Fixed
18
+ - Importmap crash (`Errno::EISDIR`) — removed invalid directory path from `importmap.paths`
19
+
10
20
  ## [0.2.7] - 2026-05-29
11
21
 
12
22
  ### Added
data/README.md CHANGED
@@ -37,6 +37,36 @@ The generator:
37
37
 
38
38
  When the gem is updated, both CSS and JS are picked up automatically — no further changes needed. Safe to re-run after upgrades.
39
39
 
40
+ ### Alternative: npm package (Vite)
41
+
42
+ The above (importmap) setup needs no npm install — the gem ships the controllers itself. If your app bundles JavaScript with Vite instead, run the install generator: it detects Vite, **installs the `@jetrockets/jet_ui` npm package** for you (running `yarn add @jetrockets/jet_ui`, or the npm/pnpm/bun equivalent it detects), and prints the wiring steps:
43
+
44
+ ```bash
45
+ rails generate jet_ui:install
46
+ # detects Vite → runs: yarn add @jetrockets/jet_ui
47
+ ```
48
+
49
+ Then register the controllers you use (`@hotwired/stimulus` is a peer dependency):
50
+
51
+ ```javascript
52
+ import { ModalController } from "@jetrockets/jet_ui"
53
+
54
+ application.register("modal", ModalController)
55
+ ```
56
+
57
+ Import the component styles in your Tailwind/CSS entry point:
58
+
59
+ ```css
60
+ @import "@jetrockets/jet_ui/css";
61
+ ```
62
+
63
+ Or, if you'd rather manage styles through the bundler than the Rails asset pipeline, import the CSS straight from JavaScript:
64
+
65
+ ```javascript
66
+ import "@jetrockets/jet_ui/css" // all component styles
67
+ import "@jetrockets/jet_ui/css/btn.css" // a single component
68
+ ```
69
+
40
70
  ## Usage
41
71
 
42
72
  The `jet_ui` helper is available in all views:
@@ -2,6 +2,7 @@
2
2
 
3
3
  require 'rails/generators'
4
4
  require_relative '../eject/eject_generator'
5
+ require_relative '../js_runtime'
5
6
 
6
7
  module JetUi
7
8
  module Generators
@@ -12,24 +13,28 @@ module JetUi
12
13
  class InstallGenerator < Rails::Generators::Base
13
14
  source_root File.expand_path('templates', __dir__)
14
15
 
16
+ class_option :skip_install, type: :boolean, default: false,
17
+ desc: 'Vite apps: skip running the package manager install, just print the command'
18
+
15
19
  desc <<~DESC
16
20
  JetUi is a ViewComponent-based UI library for Rails — #{EjectGenerator::MANIFEST.size} ready-made
17
21
  components styled with Tailwind CSS v4, matching the design system at
18
22
  ui.jetrockets.com.
19
23
 
20
- This generator sets up JetUi in your Rails application:
24
+ This generator detects how your app manages JavaScript and sets JetUi up
25
+ accordingly — no flags needed:
21
26
 
22
- 1. CSSDetects your Tailwind source file and injects a single @import
23
- that covers all JetUi component stylesheets. New components added in
24
- future gem updates are picked up automatically on the next CSS build.
27
+ Importmap apps injects the gem's CSS @import into your Tailwind source
28
+ and adds eagerLoadControllersFrom("jet_ui", application) to your Stimulus
29
+ controllers index. Controllers are auto-registered, no npm needed.
25
30
 
26
- 2. JSAdds eagerLoadControllersFrom("jet_ui", application) to your
27
- Stimulus controllers index. All current and future JetUi Stimulus
28
- controllers are registered automatically when you update the gem.
31
+ Vite apps installs the npm package with your package manager and
32
+ prints the controller registration and stylesheet @import. Vite apps own
33
+ their JS/CSS entry points, so those are not modified automatically.
29
34
 
30
- Safe to run multiple times — already-configured steps are skipped.
35
+ Safe to run multiple times — already-configured importmap steps are skipped.
31
36
 
32
- Supported Tailwind source file locations:
37
+ Importmap Tailwind source files detected for the CSS @import:
33
38
  app/assets/tailwind/application.css
34
39
  app/assets/stylesheets/application.tailwind.css
35
40
  app/assets/stylesheets/application.postcss.css
@@ -41,40 +46,19 @@ module JetUi
41
46
  rails generate jet_ui:install
42
47
  DESC
43
48
 
44
- def inject_css
45
- if (file = tailwind_source_file)
46
- content = File.read(File.join(destination_root, file))
47
- if content.include?('jet_ui')
48
- say " JetUi CSS already imported in #{file}", :yellow
49
- else
50
- # Tailwind CSS v4: import each file with an absolute path so the
51
- # Tailwind CLI can process @apply directives at build time.
52
- append_to_file file, tailwind_imports
53
- say " Injected JetUi imports into #{file}", :green
54
- end
55
- else
56
- say ' Could not detect a Tailwind CSS source file.', :yellow
57
- say ' Add the following to your Tailwind CSS source manually:', :yellow
58
- say tailwind_imports, :yellow
49
+ def show_runtime
50
+ case js_runtime
51
+ when :importmap then say ' Detected importmap — wiring JetUi via the gem.', :green
52
+ when :vite then say ' Detected Vite — wiring JetUi via the npm package.', :green
53
+ else say ' Could not detect importmap or Vite — printing both setups.', :yellow
59
54
  end
60
55
  end
61
56
 
62
- def inject_js
63
- path = File.join(destination_root, JS_CONTROLLERS_FILE)
64
- unless File.exist?(path)
65
- say ' No Stimulus controllers index found — skipping JS setup.', :yellow
66
- say ' If you use Stimulus, add this line to your controllers index manually:', :yellow
67
- say %( eagerLoadControllersFrom("jet_ui", application)), :yellow
68
- return
69
- end
70
-
71
- if File.read(path).include?('jet_ui')
72
- say " JetUi controllers already registered in #{JS_CONTROLLERS_FILE}", :yellow
73
- else
74
- insert_into_file JS_CONTROLLERS_FILE, after: /eagerLoadControllersFrom\("controllers".*\n/ do
75
- %(eagerLoadControllersFrom("jet_ui", application)\n)
76
- end
77
- say " Registered JetUi controllers in #{JS_CONTROLLERS_FILE}", :green
57
+ def setup
58
+ case js_runtime
59
+ when :importmap then setup_importmap
60
+ when :vite then setup_vite
61
+ else setup_unknown
78
62
  end
79
63
  end
80
64
 
@@ -96,6 +80,8 @@ module JetUi
96
80
  say " rails generate jet_ui:eject btn card\n"
97
81
  end
98
82
 
83
+ NPM_PACKAGE = '@jetrockets/jet_ui'
84
+
99
85
  JS_CONTROLLERS_FILE = 'app/javascript/controllers/index.js'
100
86
 
101
87
  TAILWIND_SOURCE_FILES = %w[
@@ -106,10 +92,94 @@ module JetUi
106
92
 
107
93
  private
108
94
 
95
+ def js_runtime
96
+ @js_runtime ||= JsRuntime.detect(destination_root)
97
+ end
98
+
99
+ # --- importmap: auto-wire from the gem -------------------------------
100
+
101
+ def setup_importmap
102
+ inject_importmap_css
103
+ inject_importmap_controllers
104
+ end
105
+
106
+ def inject_importmap_css
107
+ file = tailwind_source_file
108
+ unless file
109
+ say ' Could not detect a Tailwind CSS source file.', :yellow
110
+ say ' Add the following to your Tailwind CSS source manually:', :yellow
111
+ say gem_css_import, :yellow
112
+ return
113
+ end
114
+
115
+ if File.read(File.join(destination_root, file)).include?('jet_ui')
116
+ say " JetUi CSS already imported in #{file}", :yellow
117
+ else
118
+ # Tailwind CSS v4: import the gem's stylesheet by absolute path so the
119
+ # Tailwind CLI can process its @apply directives at build time.
120
+ append_to_file file, gem_css_import
121
+ say " Injected JetUi CSS into #{file}", :green
122
+ end
123
+ end
124
+
125
+ def inject_importmap_controllers
126
+ path = File.join(destination_root, JS_CONTROLLERS_FILE)
127
+ unless File.exist?(path)
128
+ say ' No Stimulus controllers index found — add this line to it manually:', :yellow
129
+ say %( eagerLoadControllersFrom("jet_ui", application)), :yellow
130
+ return
131
+ end
132
+
133
+ if File.read(path).include?('jet_ui')
134
+ say " JetUi controllers already registered in #{JS_CONTROLLERS_FILE}", :yellow
135
+ else
136
+ insert_into_file JS_CONTROLLERS_FILE, after: /eagerLoadControllersFrom\("controllers".*\n/ do
137
+ %(eagerLoadControllersFrom("jet_ui", application)\n)
138
+ end
139
+ say " Registered JetUi controllers in #{JS_CONTROLLERS_FILE}", :green
140
+ end
141
+ end
142
+
143
+ # --- vite: install the package, but never touch the app's entry points ---
144
+
145
+ def setup_vite
146
+ install_npm_package
147
+ say ' Ensure @hotwired/stimulus is installed — it is a peer dependency the controllers import.', :yellow
148
+ say ' Register the controllers you use, in your Stimulus controllers index:'
149
+ say %( import { ModalController, DrawerController } from "#{NPM_PACKAGE}")
150
+ say %( application.register("modal", ModalController))
151
+ say %( application.register("drawer", DrawerController))
152
+ say ' Import the styles, in your Tailwind/CSS entry point:'
153
+ say %( @import "#{NPM_PACKAGE}/css";)
154
+ end
155
+
156
+ def install_npm_package
157
+ command = JsRuntime.install_command(destination_root, NPM_PACKAGE)
158
+ if options[:skip_install]
159
+ say ' Skipped install — run it yourself:', :yellow
160
+ say " #{command}"
161
+ else
162
+ say " Installing #{NPM_PACKAGE}…", :green
163
+ run command
164
+ end
165
+ end
166
+
167
+ def setup_unknown
168
+ say ' Importmap apps — add to your Stimulus controllers index:', :yellow
169
+ say %( eagerLoadControllersFrom("jet_ui", application))
170
+ say ' Vite apps — install the npm package and import its styles:', :yellow
171
+ say " #{JsRuntime.install_command(destination_root, NPM_PACKAGE)}"
172
+ say %( @import "#{NPM_PACKAGE}/css";)
173
+ end
174
+
109
175
  def tailwind_source_file
110
176
  TAILWIND_SOURCE_FILES.find { |f| File.exist?(File.join(destination_root, f)) }
111
177
  end
112
178
 
179
+ def gem_css_import
180
+ %(\n@import "#{File.join(gem_stylesheets_path, 'jet_ui.css')}";\n)
181
+ end
182
+
113
183
  def gem_stylesheets_path
114
184
  spec = begin
115
185
  Gem::Specification.find_by_name('jet_ui')
@@ -119,10 +189,6 @@ module JetUi
119
189
  base = spec&.gem_dir || File.expand_path('../../../../..', __dir__)
120
190
  File.join(base, 'app/assets/stylesheets')
121
191
  end
122
-
123
- def tailwind_imports
124
- %(\n@import "#{File.join(gem_stylesheets_path, 'jet_ui.css')}";\n)
125
- end
126
192
  end
127
193
  end
128
194
  end
@@ -0,0 +1,81 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'json'
4
+
5
+ module JetUi
6
+ module Generators
7
+ # Detects how a host application manages its JavaScript, so the install
8
+ # generator can wire JetUi the right way without asking: pin controllers via
9
+ # importmap, or point the app at the npm package for Vite.
10
+ module JsRuntime
11
+ VITE_CONFIGS = %w[
12
+ vite.config.js vite.config.mjs vite.config.ts
13
+ config/vite.json
14
+ ].freeze
15
+
16
+ # Ordered: the first lockfile found wins.
17
+ PACKAGE_MANAGERS = {
18
+ 'bun.lockb' => :bun,
19
+ 'pnpm-lock.yaml' => :pnpm,
20
+ 'yarn.lock' => :yarn,
21
+ 'package-lock.json' => :npm
22
+ }.freeze
23
+
24
+ module_function
25
+
26
+ # Vite wins when both are present: a working Vite config is a stronger
27
+ # signal than a leftover config/importmap.rb.
28
+ def detect(root)
29
+ return :vite if vite?(root)
30
+ return :importmap if importmap?(root)
31
+
32
+ :unknown
33
+ end
34
+
35
+ def vite?(root)
36
+ VITE_CONFIGS.any? { |file| File.exist?(File.join(root, file)) } ||
37
+ package_json_vite?(root)
38
+ end
39
+
40
+ def importmap?(root)
41
+ File.exist?(File.join(root, 'config/importmap.rb'))
42
+ end
43
+
44
+ def package_manager(root)
45
+ PACKAGE_MANAGERS.each { |lock, name| return name if File.exist?(File.join(root, lock)) }
46
+ package_manager_field(root) || :npm
47
+ end
48
+
49
+ # corepack's `"packageManager": "yarn@4.5.0"` — the declared manager when
50
+ # there's no lockfile yet (e.g. a fresh vite_rails clone).
51
+ def package_manager_field(root)
52
+ path = File.join(root, 'package.json')
53
+ return unless File.exist?(path)
54
+
55
+ field = JSON.parse(File.read(path))['packageManager']
56
+ return unless field
57
+
58
+ PACKAGE_MANAGERS.values.find { |name| name.to_s == field.split('@').first }
59
+ rescue JSON::ParserError
60
+ nil
61
+ end
62
+
63
+ def install_command(root, package)
64
+ manager = package_manager(root)
65
+ verb = manager == :npm ? 'install' : 'add'
66
+
67
+ "#{manager} #{verb} #{package}"
68
+ end
69
+
70
+ def package_json_vite?(root)
71
+ path = File.join(root, 'package.json')
72
+ return false unless File.exist?(path)
73
+
74
+ deps = JSON.parse(File.read(path)).values_at('dependencies', 'devDependencies').compact
75
+ deps.flat_map(&:keys).include?('vite')
76
+ rescue JSON::ParserError
77
+ false
78
+ end
79
+ end
80
+ end
81
+ end
data/lib/jet_ui/engine.rb CHANGED
@@ -17,7 +17,6 @@ module JetUi
17
17
  root.join('app/assets/javascripts/jet_ui'),
18
18
  under: 'jet_ui'
19
19
  )
20
- app.config.importmap.paths << root.join('app/assets/javascripts')
21
20
  app.config.importmap.cache_sweepers << root.join('app/assets/javascripts')
22
21
  end
23
22
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module JetUi
4
- VERSION = '0.2.7'
4
+ VERSION = '0.2.8'
5
5
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: jet_ui
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.7
4
+ version: 0.2.8
5
5
  platform: ruby
6
6
  authors:
7
7
  - JetRockets
@@ -635,6 +635,7 @@ files:
635
635
  - app/helpers/jet_ui_helper.rb
636
636
  - lib/generators/jet_ui/eject/eject_generator.rb
637
637
  - lib/generators/jet_ui/install/install_generator.rb
638
+ - lib/generators/jet_ui/js_runtime.rb
638
639
  - lib/jet_ui.rb
639
640
  - lib/jet_ui/engine.rb
640
641
  - lib/jet_ui/version.rb