turbo-mount 0.2.3 → 0.3.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +20 -4
- data/README.md +94 -66
- data/app/assets/javascripts/turbo-mount/react.js +8 -19
- data/app/assets/javascripts/turbo-mount/react.min.js +1 -1
- data/app/assets/javascripts/turbo-mount/react.min.js.map +1 -1
- data/app/assets/javascripts/turbo-mount/svelte.js +8 -19
- data/app/assets/javascripts/turbo-mount/svelte.min.js +1 -1
- data/app/assets/javascripts/turbo-mount/svelte.min.js.map +1 -1
- data/app/assets/javascripts/turbo-mount/vue.js +8 -19
- data/app/assets/javascripts/turbo-mount/vue.min.js +1 -1
- data/app/assets/javascripts/turbo-mount/vue.min.js.map +1 -1
- data/app/assets/javascripts/turbo-mount.js +53 -26
- data/app/assets/javascripts/turbo-mount.min.js +1 -1
- data/app/assets/javascripts/turbo-mount.min.js.map +1 -1
- data/lib/generators/turbo_mount/install/turbo-mount.js.tt +18 -0
- data/lib/generators/turbo_mount/install_generator.rb +112 -0
- data/lib/turbo/mount/helpers.rb +3 -14
- data/lib/turbo/mount/version.rb +1 -1
- metadata +4 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 3565dc0d8e80907e11600573cfb18049fe5360c9551facefb9a22d871bebad2e
|
4
|
+
data.tar.gz: 2e82006304c22c3b663511abbefaee3a0fc8e96aa972b044e1fca640cfd9c262
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 2490534f21cf102b00c00524457be4b6b6f3d048e2d0477ad20bdbf2818704d5b39580bc9f71d5f33de6f39fcdd97faa20e0c0cc05a3c338225091e1096fa428
|
7
|
+
data.tar.gz: 6154769b9a73b2bf3e65e0c6a395a154109466d698f79dc5483378ed7f68cce060c41183725f240fff942a3cf09e03ac909b2f0d0f0da70a574a6712e28e1251
|
data/CHANGELOG.md
CHANGED
@@ -7,6 +7,21 @@ and this project adheres to [Semantic Versioning].
|
|
7
7
|
|
8
8
|
## [Unreleased]
|
9
9
|
|
10
|
+
## [0.3.0] - 2024-05-31
|
11
|
+
|
12
|
+
### Added
|
13
|
+
|
14
|
+
- Installation script. ([@skryukov])
|
15
|
+
|
16
|
+
### Changed
|
17
|
+
|
18
|
+
- [BREAKING] New API without controller inheritance. ([@skryukov])
|
19
|
+
To migrate to the new API:
|
20
|
+
- Replace `new TurboMountReact()` (or any other framework specific constructor) with `new TurboMount()`
|
21
|
+
- Replace `turboMount.register(...)` with `registerComponent(turboMount, ...)`
|
22
|
+
- Replace `turbo_mount_react_component` (or any other framework specific helper) with `turbo_mount`
|
23
|
+
- Also see the new API for plugins and custom controllers in the README.
|
24
|
+
|
10
25
|
## [0.2.3] - 2024-05-12
|
11
26
|
|
12
27
|
### Added
|
@@ -36,10 +51,11 @@ and this project adheres to [Semantic Versioning].
|
|
36
51
|
|
37
52
|
[@skryukov]: https://github.com/skryukov
|
38
53
|
|
39
|
-
[Unreleased]: https://github.com/skryukov/turbo-mount/compare/v0.
|
40
|
-
[0.
|
41
|
-
[0.2.
|
42
|
-
[0.2.
|
54
|
+
[Unreleased]: https://github.com/skryukov/turbo-mount/compare/v0.3.0...HEAD
|
55
|
+
[0.3.0]: https://github.com/skryukov/turbo-mount/compare/v0.2.3...v0.3.0
|
56
|
+
[0.2.3]: https://github.com/skryukov/turbo-mount/compare/v0.2.2...v0.2.3
|
57
|
+
[0.2.2]: https://github.com/skryukov/turbo-mount/compare/v0.2.0...v0.2.2
|
58
|
+
[0.2.0]: https://github.com/skryukov/turbo-mount/compare/v0.1.0...v0.2.0
|
43
59
|
[0.1.0]: https://github.com/skryukov/turbo-mount/commits/v0.1.0
|
44
60
|
|
45
61
|
[Keep a Changelog]: https://keepachangelog.com/en/1.0.0/
|
data/README.md
CHANGED
@@ -1,104 +1,143 @@
|
|
1
|
-
# Turbo
|
1
|
+
# Turbo Mount
|
2
2
|
|
3
3
|
[![Gem Version](https://badge.fury.io/rb/turbo-mount.svg)](https://rubygems.org/gems/turbo-mount)
|
4
4
|
|
5
|
-
`
|
5
|
+
`TurboMount` is a simple library that allows you to add highly interactive components from React, Vue, Svelte, and other frameworks to your Hotwire application.
|
6
|
+
|
7
|
+
## Table of Contents
|
8
|
+
- [Installation](#installation)
|
9
|
+
- [Importmaps](#importmaps)
|
10
|
+
- [Usage](#usage)
|
11
|
+
- [Initialization](#initialization)
|
12
|
+
- [Standard Initialization](#standard-initialization)
|
13
|
+
- [Simplified Initialization](#simplified-initialization)
|
14
|
+
- [Plugin-Specific Initialization](#plugin-specific-initialization)
|
15
|
+
- [View Helpers](#view-helpers)
|
16
|
+
- [Supported Frameworks](#supported-frameworks)
|
17
|
+
- [Custom Controllers](#custom-controllers)
|
18
|
+
- [Vite Integration](#vite-integration)
|
19
|
+
- [Mount Target](#mount-target)
|
20
|
+
- [License](#license)
|
21
|
+
|
22
|
+
<a href="https://evilmartians.com/?utm_source=turbo-mount&utm_campaign=project_page">
|
23
|
+
<img src="https://evilmartians.com/badges/sponsored-by-evil-martians.svg" alt="Built by Evil Martians" width="236" height="54">
|
24
|
+
</a>
|
6
25
|
|
7
26
|
## Installation
|
8
27
|
|
9
|
-
|
28
|
+
To install Turbo Mount, add the following line to your `Gemfile` and run `bundle install`:
|
10
29
|
|
11
30
|
```ruby
|
12
31
|
gem "turbo-mount"
|
13
32
|
```
|
14
33
|
|
15
|
-
|
34
|
+
### Automatic Installation
|
35
|
+
|
36
|
+
Run the following command to install the necessary files:
|
16
37
|
|
17
38
|
```bash
|
18
|
-
|
19
|
-
# or with yarn
|
20
|
-
yarn add turbo-mount
|
39
|
+
bin/rails generate turbo_mount:install
|
21
40
|
```
|
22
41
|
|
23
|
-
|
42
|
+
This will add `turbo-mount` package and framework dependencies to your `package.json` or `importmap.rb`, and create the Turbo Mount initialization file.
|
24
43
|
|
25
|
-
###
|
44
|
+
### Manual Installation
|
26
45
|
|
27
|
-
|
46
|
+
You can also install the necessary JavaScript files manually.
|
28
47
|
|
29
|
-
|
48
|
+
If your project utilizes build tools such as [Vite](http://vite-ruby.netlify.app), also install the `turbo-mount` package:
|
30
49
|
|
31
|
-
|
50
|
+
```bash
|
51
|
+
npm install turbo-mount
|
52
|
+
# or with yarn
|
53
|
+
yarn add turbo-mount
|
32
54
|
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
55
|
+
# and the desired framework
|
56
|
+
npm install react react-dom
|
57
|
+
# or
|
58
|
+
npm install vue
|
59
|
+
# or
|
60
|
+
npm install svelte
|
61
|
+
```
|
62
|
+
|
63
|
+
If you're using Vite, don't forget to add [framework-specific plugins](https://vitejs.dev/plugins) to your `vite.config.js`.
|
38
64
|
|
39
|
-
|
40
|
-
|
65
|
+
### Importmaps
|
66
|
+
To use `TurboMount` with importmaps, you need to pin the necessary JavaScript files in your `config/importmap.rb`:
|
41
67
|
|
42
|
-
|
68
|
+
```ruby
|
69
|
+
pin "turbo-mount", to: "turbo-mount.min.js"
|
70
|
+
pin "turbo-mount/react", to: "turbo-mount/react.min.js"
|
43
71
|
```
|
44
72
|
|
45
|
-
|
73
|
+
This ensures that `turbo-mount` and its plugins are available in your application.
|
46
74
|
|
47
|
-
|
75
|
+
Also pin the desired framework:
|
48
76
|
|
49
|
-
```
|
50
|
-
|
51
|
-
|
52
|
-
|
77
|
+
```bash
|
78
|
+
bin/importmap pin react react-dom react-dom/client
|
79
|
+
# or
|
80
|
+
bin/importmap pin vue
|
81
|
+
# or
|
82
|
+
bin/importmap pin svelte
|
83
|
+
```
|
53
84
|
|
54
|
-
|
85
|
+
Note: Importmap-only mode is quite limited in terms of JavaScript dependencies. If you're using a more complex setup, consider using a bundler like Vite.
|
55
86
|
|
56
|
-
|
57
|
-
```
|
87
|
+
## Usage
|
58
88
|
|
59
|
-
|
89
|
+
### Initialization
|
60
90
|
|
61
|
-
|
91
|
+
To begin using `TurboMount`, start by initializing the library and registering the components you intend to use. Here's how to set it up with a React plugin:
|
62
92
|
|
63
93
|
```js
|
64
|
-
import {
|
65
|
-
import {
|
94
|
+
import { TurboMount } from "turbo-mount";
|
95
|
+
import { registerComponent } from "turbo-mount/react";
|
96
|
+
import { HexColorPicker } from 'react-colorful';
|
66
97
|
|
67
|
-
const turboMount = new
|
98
|
+
const turboMount = new TurboMount(); // or new TurboMount({ application })
|
68
99
|
|
69
|
-
turboMount
|
100
|
+
registerComponent(turboMount, "HexColorPicker", HexColorPicker);
|
70
101
|
```
|
71
102
|
|
103
|
+
If you prefer not to specify the `application` explicitly, `TurboMount` can automatically detect or initialize it. Turbo Mount uses the `window.Stimulus` if available; otherwise, it initializes a new Stimulus application.
|
104
|
+
|
72
105
|
### View Helpers
|
73
106
|
|
74
107
|
Use the following helpers to mount components in your views:
|
75
108
|
|
76
109
|
```erb
|
77
|
-
<%=
|
110
|
+
<%= turbo_mount("HexColorPicker", props: {color: "#034"}, class: "mb-5") %>
|
111
|
+
```
|
78
112
|
|
79
|
-
|
113
|
+
This will generate the following HTML:
|
80
114
|
|
81
|
-
|
115
|
+
```html
|
116
|
+
<div data-controller="turbo-mount-hex-color-picker"
|
117
|
+
data-turbo-mount-hex-color-picker-component-value="HexColorPicker"
|
118
|
+
data-turbo-mount-hex-color-picker-props-value="{"color":"#034"}"
|
119
|
+
class="mb-5">
|
120
|
+
</div>
|
82
121
|
```
|
83
122
|
|
84
123
|
### Supported Frameworks
|
85
124
|
|
86
125
|
`TurboMount` supports the following frameworks:
|
87
126
|
|
88
|
-
- React `"turbo-mount/react"`
|
89
|
-
- Vue `"turbo-mount/vue"`
|
90
|
-
- Svelte `"turbo-mount/svelte"`
|
127
|
+
- React: `"turbo-mount/react"`
|
128
|
+
- Vue: `"turbo-mount/vue"`
|
129
|
+
- Svelte: `"turbo-mount/svelte"`
|
91
130
|
|
92
|
-
|
131
|
+
To add support for other frameworks, create a custom plugin. See included plugins for examples.
|
93
132
|
|
94
133
|
### Custom Controllers
|
95
134
|
|
96
135
|
To customize component behavior or pass functions as props, create a custom controller:
|
97
136
|
|
98
137
|
```js
|
99
|
-
import {
|
138
|
+
import { TurboMountController } from "turbo-mount";
|
100
139
|
|
101
|
-
export default class extends
|
140
|
+
export default class extends TurboMountController {
|
102
141
|
get componentProps() {
|
103
142
|
return {
|
104
143
|
...this.propsValue,
|
@@ -107,62 +146,51 @@ export default class extends TurboMountReactController {
|
|
107
146
|
}
|
108
147
|
|
109
148
|
onChange = (color) => {
|
110
|
-
this.propsValue = { ...this.propsValue, color
|
149
|
+
// same as this.propsValue = { ...this.propsValue, color };
|
150
|
+
// but skips the rerendering of the component:
|
151
|
+
this.componentProps = { ...this.propsValue, color };
|
111
152
|
};
|
112
153
|
}
|
113
154
|
```
|
114
155
|
|
115
|
-
Then pass this controller the
|
156
|
+
Then pass this controller to the `registerComponent` method:
|
116
157
|
|
117
158
|
```js
|
118
|
-
import
|
159
|
+
import HexColorPickerController from "controllers/turbo_mount/hex_color_picker_controller";
|
119
160
|
|
120
|
-
turboMount
|
161
|
+
registerComponent(turboMount, "HexColorPicker", HexColorPicker, HexColorPickerController);
|
121
162
|
```
|
122
163
|
|
123
164
|
### Vite Integration
|
124
165
|
|
125
|
-
`TurboMount` includes a `registerComponents` function that automates the loading of components (requires `stimulus-vite-helpers` package). It also accepts an optional `controllers` property to autoload customized controllers:
|
166
|
+
`TurboMount` includes a `registerComponents` function that automates the loading of components (requires the `stimulus-vite-helpers` package). It also accepts an optional `controllers` property to autoload customized controllers:
|
126
167
|
|
127
168
|
```js
|
128
169
|
import { TurboMount } from "turbo-mount/react";
|
129
|
-
import { registerComponents } from "turbo-mount/
|
170
|
+
import { registerComponents } from "turbo-mount/registerComponents/react";
|
130
171
|
|
131
172
|
const controllers = import.meta.glob("./**/*_controller.js", { eager: true });
|
132
|
-
const components = import.meta.glob(
|
173
|
+
const components = import.meta.glob("/components/**/*.jsx", { eager: true });
|
133
174
|
|
134
175
|
const turboMount = new TurboMount();
|
135
176
|
registerComponents({ turboMount, components, controllers });
|
136
177
|
```
|
137
178
|
|
138
179
|
The `registerComponents` helper searches for controllers in the following paths:
|
139
|
-
- `controllers/turbo-mount/${framework}/${controllerName}`
|
140
|
-
- `controllers/turbo-mount/${framework}-${controllerName}`
|
141
|
-
- `controllers/turbo-mount-${framework}-${controllerName}`
|
142
180
|
- `controllers/turbo-mount/${controllerName}`
|
143
181
|
- `controllers/turbo-mount-${controllerName}`
|
144
182
|
|
145
|
-
### Mount
|
183
|
+
### Mount Target
|
146
184
|
|
147
185
|
To specify a non-root mount target, use the `data-<%= controller_name %>-target="mount"` attribute:
|
148
186
|
|
149
187
|
```erb
|
150
|
-
<%=
|
188
|
+
<%= turbo_mount("HexColorPicker", props: {color: "#430"}) do |controller_name| %>
|
151
189
|
<h3>Color picker</h3>
|
152
190
|
<div data-<%= controller_name %>-target="mount"></div>
|
153
191
|
<% end %>
|
154
192
|
```
|
155
193
|
|
156
|
-
## Development
|
157
|
-
|
158
|
-
After checking out the repo, run `bin/setup` to install dependencies. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
|
159
|
-
|
160
|
-
To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and the created tag, and push the `.gem` file to [rubygems.org](https://rubygems.org).
|
161
|
-
|
162
|
-
## Contributing
|
163
|
-
|
164
|
-
Bug reports and pull requests are welcome on GitHub at https://github.com/skryukov/turbo-mount.
|
165
|
-
|
166
194
|
## License
|
167
195
|
|
168
196
|
The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
|
@@ -1,29 +1,18 @@
|
|
1
|
-
import {
|
1
|
+
import { buildRegisterFunction } from 'turbo-mount';
|
2
|
+
export { TurboMount } from 'turbo-mount';
|
2
3
|
import { createElement } from 'react';
|
3
4
|
import { createRoot } from 'react-dom/client';
|
4
5
|
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
this.framework = "react";
|
9
|
-
}
|
10
|
-
mountComponent(el, Component, props) {
|
6
|
+
const plugin = {
|
7
|
+
mountComponent: (mountProps) => {
|
8
|
+
const { el, Component, props } = mountProps;
|
11
9
|
const root = createRoot(el);
|
12
10
|
root.render(createElement(Component, props));
|
13
11
|
return () => {
|
14
12
|
root.unmount();
|
15
13
|
};
|
16
|
-
}
|
17
|
-
}
|
18
|
-
|
19
|
-
const plugin = {
|
20
|
-
framework: "react",
|
21
|
-
controller: TurboMountReactController,
|
14
|
+
},
|
22
15
|
};
|
23
|
-
|
24
|
-
constructor(props) {
|
25
|
-
super(Object.assign(Object.assign({}, props), { plugin }));
|
26
|
-
}
|
27
|
-
}
|
16
|
+
const registerComponent = buildRegisterFunction(plugin);
|
28
17
|
|
29
|
-
export {
|
18
|
+
export { plugin as default, registerComponent };
|
@@ -1,2 +1,2 @@
|
|
1
|
-
import{
|
1
|
+
import{buildRegisterFunction as o}from"turbo-mount";export{TurboMount}from"turbo-mount";import{createElement as t}from"react";import{createRoot as r}from"react-dom/client";const n={mountComponent:o=>{const{el:n,Component:m,props:e}=o,u=r(n);return u.render(t(m,e)),()=>{u.unmount()}}},m=o(n);export{n as default,m as registerComponent};
|
2
2
|
//# sourceMappingURL=react.min.js.map
|
@@ -1 +1 @@
|
|
1
|
-
{"version":3,"file":"react.min.js","sources":["../../src/plugins/react/index.ts"
|
1
|
+
{"version":3,"file":"react.min.js","sources":["../../src/plugins/react/index.ts"],"sourcesContent":["import { buildRegisterFunction, Plugin, TurboMount } from \"turbo-mount\";\nimport { ComponentType, createElement } from \"react\";\nimport { createRoot } from \"react-dom/client\";\n\nconst plugin: Plugin<ComponentType> = {\n mountComponent: (mountProps) => {\n const { el, Component, props } = mountProps;\n const root = createRoot(el);\n root.render(createElement(Component, props));\n\n return () => {\n root.unmount();\n };\n },\n};\n\nconst registerComponent = buildRegisterFunction(plugin);\n\nexport { TurboMount, registerComponent };\n\nexport default plugin;\n"],"names":["plugin","mountComponent","mountProps","el","Component","props","root","createRoot","render","createElement","unmount","registerComponent","buildRegisterFunction"],"mappings":"4KAIA,MAAMA,EAAgC,CACpCC,eAAiBC,IACf,MAAMC,GAAEA,EAAEC,UAAEA,EAASC,MAAEA,GAAUH,EAC3BI,EAAOC,EAAWJ,GAGxB,OAFAG,EAAKE,OAAOC,EAAcL,EAAWC,IAE9B,KACLC,EAAKI,SAAS,CACf,GAICC,EAAoBC,EAAsBZ"}
|
@@ -1,26 +1,15 @@
|
|
1
|
-
import {
|
1
|
+
import { buildRegisterFunction } from 'turbo-mount';
|
2
|
+
export { TurboMount } from 'turbo-mount';
|
2
3
|
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
this.framework = "svelte";
|
7
|
-
}
|
8
|
-
mountComponent(el, Component, props) {
|
4
|
+
const plugin = {
|
5
|
+
mountComponent: (mountProps) => {
|
6
|
+
const { el, Component, props } = mountProps;
|
9
7
|
const component = new Component({ target: el, props });
|
10
8
|
return () => {
|
11
9
|
component.$destroy();
|
12
10
|
};
|
13
|
-
}
|
14
|
-
}
|
15
|
-
|
16
|
-
const plugin = {
|
17
|
-
framework: "svelte",
|
18
|
-
controller: TurboMountSvelteController,
|
11
|
+
},
|
19
12
|
};
|
20
|
-
|
21
|
-
constructor(props) {
|
22
|
-
super(Object.assign(Object.assign({}, props), { plugin }));
|
23
|
-
}
|
24
|
-
}
|
13
|
+
const registerComponent = buildRegisterFunction(plugin);
|
25
14
|
|
26
|
-
export {
|
15
|
+
export { plugin as default, registerComponent };
|
@@ -1,2 +1,2 @@
|
|
1
|
-
import{
|
1
|
+
import{buildRegisterFunction as o}from"turbo-mount";export{TurboMount}from"turbo-mount";const t={mountComponent:o=>{const{el:t,Component:r,props:n}=o,e=new r({target:t,props:n});return()=>{e.$destroy()}}},r=o(t);export{t as default,r as registerComponent};
|
2
2
|
//# sourceMappingURL=svelte.min.js.map
|
@@ -1 +1 @@
|
|
1
|
-
{"version":3,"file":"svelte.min.js","sources":["../../src/plugins/svelte/index.ts"
|
1
|
+
{"version":3,"file":"svelte.min.js","sources":["../../src/plugins/svelte/index.ts"],"sourcesContent":["import { buildRegisterFunction, Plugin, TurboMount } from \"turbo-mount\";\nimport { ComponentType } from \"svelte\";\n\nconst plugin: Plugin<ComponentType> = {\n mountComponent: (mountProps) => {\n const { el, Component, props } = mountProps;\n const component = new Component({ target: el, props });\n\n return () => {\n component.$destroy();\n };\n },\n};\n\nconst registerComponent = buildRegisterFunction(plugin);\n\nexport { TurboMount, registerComponent };\n\nexport default plugin;\n"],"names":["plugin","mountComponent","mountProps","el","Component","props","component","target","$destroy","registerComponent","buildRegisterFunction"],"mappings":"wFAGA,MAAMA,EAAgC,CACpCC,eAAiBC,IACf,MAAMC,GAAEA,EAAEC,UAAEA,EAASC,MAAEA,GAAUH,EAC3BI,EAAY,IAAIF,EAAU,CAAEG,OAAQJ,EAAIE,UAE9C,MAAO,KACLC,EAAUE,UAAU,CACrB,GAICC,EAAoBC,EAAsBV"}
|
@@ -1,28 +1,17 @@
|
|
1
|
-
import {
|
1
|
+
import { buildRegisterFunction } from 'turbo-mount';
|
2
|
+
export { TurboMount } from 'turbo-mount';
|
2
3
|
import { createApp } from 'vue';
|
3
4
|
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
this.framework = "vue";
|
8
|
-
}
|
9
|
-
mountComponent(el, Component, props) {
|
5
|
+
const plugin = {
|
6
|
+
mountComponent: (mountProps) => {
|
7
|
+
const { el, Component, props } = mountProps;
|
10
8
|
const app = createApp(Component, props);
|
11
9
|
app.mount(el);
|
12
10
|
return () => {
|
13
11
|
app.unmount();
|
14
12
|
};
|
15
|
-
}
|
16
|
-
}
|
17
|
-
|
18
|
-
const plugin = {
|
19
|
-
framework: "vue",
|
20
|
-
controller: TurboMountVueController,
|
13
|
+
},
|
21
14
|
};
|
22
|
-
|
23
|
-
constructor(props) {
|
24
|
-
super(Object.assign(Object.assign({}, props), { plugin }));
|
25
|
-
}
|
26
|
-
}
|
15
|
+
const registerComponent = buildRegisterFunction(plugin);
|
27
16
|
|
28
|
-
export {
|
17
|
+
export { plugin as default, registerComponent };
|
@@ -1,2 +1,2 @@
|
|
1
|
-
import{
|
1
|
+
import{buildRegisterFunction as o}from"turbo-mount";export{TurboMount}from"turbo-mount";import{createApp as t}from"vue";const n={mountComponent:o=>{const{el:n,Component:r,props:u}=o,m=t(r,u);return m.mount(n),()=>{m.unmount()}}},r=o(n);export{n as default,r as registerComponent};
|
2
2
|
//# sourceMappingURL=vue.min.js.map
|
@@ -1 +1 @@
|
|
1
|
-
{"version":3,"file":"vue.min.js","sources":["../../src/plugins/vue/index.ts"
|
1
|
+
{"version":3,"file":"vue.min.js","sources":["../../src/plugins/vue/index.ts"],"sourcesContent":["import { buildRegisterFunction, Plugin, TurboMount } from \"turbo-mount\";\nimport { App, createApp } from \"vue\";\n\nconst plugin: Plugin<App> = {\n mountComponent: (mountProps) => {\n const { el, Component, props } = mountProps;\n const app = createApp(Component, props as Record<string, unknown>);\n app.mount(el);\n\n return () => {\n app.unmount();\n };\n },\n};\n\nconst registerComponent = buildRegisterFunction(plugin);\n\nexport { TurboMount, registerComponent };\n\nexport default plugin;\n"],"names":["plugin","mountComponent","mountProps","el","Component","props","app","createApp","mount","unmount","registerComponent","buildRegisterFunction"],"mappings":"wHAGA,MAAMA,EAAsB,CAC1BC,eAAiBC,IACf,MAAMC,GAAEA,EAAEC,UAAEA,EAASC,MAAEA,GAAUH,EAC3BI,EAAMC,EAAUH,EAAWC,GAGjC,OAFAC,EAAIE,MAAML,GAEH,KACLG,EAAIG,SAAS,CACd,GAICC,EAAoBC,EAAsBX"}
|
@@ -1,6 +1,10 @@
|
|
1
1
|
import { Controller, Application } from '@hotwired/stimulus';
|
2
2
|
|
3
3
|
class TurboMountController extends Controller {
|
4
|
+
constructor() {
|
5
|
+
super(...arguments);
|
6
|
+
this.skipPropsChangeCallback = false;
|
7
|
+
}
|
4
8
|
connect() {
|
5
9
|
this._umountComponentCallback || (this._umountComponentCallback = this.mountComponent(this.mountElement, this.resolvedComponent, this.componentProps));
|
6
10
|
}
|
@@ -8,6 +12,10 @@ class TurboMountController extends Controller {
|
|
8
12
|
this.umountComponent();
|
9
13
|
}
|
10
14
|
propsValueChanged() {
|
15
|
+
if (this.skipPropsChangeCallback) {
|
16
|
+
this.skipPropsChangeCallback = false;
|
17
|
+
return;
|
18
|
+
}
|
11
19
|
this.umountComponent();
|
12
20
|
this._umountComponentCallback || (this._umountComponentCallback = this.mountComponent(this.mountElement, this.resolvedComponent, this.componentProps));
|
13
21
|
}
|
@@ -18,15 +26,25 @@ class TurboMountController extends Controller {
|
|
18
26
|
return this.hasMountTarget ? this.mountTarget : this.element;
|
19
27
|
}
|
20
28
|
get resolvedComponent() {
|
21
|
-
return this.
|
29
|
+
return this.resolveMounted(this.componentValue).component;
|
30
|
+
}
|
31
|
+
get resolvedPlugin() {
|
32
|
+
return this.resolveMounted(this.componentValue).plugin;
|
22
33
|
}
|
23
34
|
umountComponent() {
|
24
35
|
this._umountComponentCallback && this._umountComponentCallback();
|
25
36
|
this._umountComponentCallback = undefined;
|
26
37
|
}
|
27
|
-
|
38
|
+
mountComponent(el, Component, props) {
|
39
|
+
return this.resolvedPlugin.mountComponent({ el, Component, props });
|
40
|
+
}
|
41
|
+
resolveMounted(component) {
|
28
42
|
const app = this.application;
|
29
|
-
return app.turboMount
|
43
|
+
return app.turboMount.resolve(component);
|
44
|
+
}
|
45
|
+
setComponentProps(props) {
|
46
|
+
this.skipPropsChangeCallback = true;
|
47
|
+
this.propsValue = props;
|
30
48
|
}
|
31
49
|
}
|
32
50
|
TurboMountController.values = {
|
@@ -40,34 +58,30 @@ const camelToKebabCase = (str) => {
|
|
40
58
|
};
|
41
59
|
|
42
60
|
class TurboMount {
|
43
|
-
constructor(
|
44
|
-
var _a;
|
61
|
+
constructor(props = {}) {
|
45
62
|
this.components = new Map();
|
46
|
-
this.application = this.findOrStartApplication(application);
|
47
|
-
this.
|
48
|
-
this.
|
49
|
-
(
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
63
|
+
this.application = this.findOrStartApplication(props.application);
|
64
|
+
this.application.turboMount = this;
|
65
|
+
this.application.register("turbo-mount", TurboMountController);
|
66
|
+
document.addEventListener("turbo:before-morph-element", (event) => {
|
67
|
+
var _a;
|
68
|
+
const turboMorphEvent = event;
|
69
|
+
const { target, detail } = turboMorphEvent;
|
70
|
+
if ((_a = target.getAttribute("data-controller")) === null || _a === void 0 ? void 0 : _a.includes("turbo-mount")) {
|
71
|
+
target.setAttribute("data-turbo-mount-props-value", detail.newElement.getAttribute("data-turbo-mount-props-value") ||
|
72
|
+
"{}");
|
73
|
+
event.preventDefault();
|
74
|
+
}
|
75
|
+
});
|
54
76
|
}
|
55
|
-
|
56
|
-
|
57
|
-
if (!application) {
|
58
|
-
application = Application.start();
|
59
|
-
window.Stimulus = application;
|
60
|
-
}
|
61
|
-
return application;
|
62
|
-
}
|
63
|
-
register(name, component, controller) {
|
64
|
-
controller || (controller = this.baseController);
|
77
|
+
register(plugin, name, component, controller) {
|
78
|
+
controller || (controller = TurboMountController);
|
65
79
|
if (this.components.has(name)) {
|
66
80
|
throw new Error(`Component '${name}' is already registered.`);
|
67
81
|
}
|
68
|
-
this.components.set(name, component);
|
82
|
+
this.components.set(name, { component, plugin });
|
69
83
|
if (controller) {
|
70
|
-
const controllerName = `turbo-mount-${
|
84
|
+
const controllerName = `turbo-mount-${camelToKebabCase(name)}`;
|
71
85
|
this.application.register(controllerName, controller);
|
72
86
|
}
|
73
87
|
}
|
@@ -78,6 +92,19 @@ class TurboMount {
|
|
78
92
|
}
|
79
93
|
return component;
|
80
94
|
}
|
95
|
+
findOrStartApplication(hydratedApp) {
|
96
|
+
let application = hydratedApp || window.Stimulus;
|
97
|
+
if (!application) {
|
98
|
+
application = Application.start();
|
99
|
+
window.Stimulus = application;
|
100
|
+
}
|
101
|
+
return application;
|
102
|
+
}
|
103
|
+
}
|
104
|
+
function buildRegisterFunction(plugin) {
|
105
|
+
return (turboMount, name, component, controller) => {
|
106
|
+
turboMount.register(plugin, name, component, controller);
|
107
|
+
};
|
81
108
|
}
|
82
109
|
|
83
|
-
export { TurboMount, TurboMountController };
|
110
|
+
export { TurboMount, TurboMountController, buildRegisterFunction };
|
@@ -1,2 +1,2 @@
|
|
1
|
-
import{Controller as t,Application as o}from"@hotwired/stimulus";class n extends t{connect(){this._umountComponentCallback||(this._umountComponentCallback=this.mountComponent(this.mountElement,this.resolvedComponent,this.componentProps))}disconnect(){this.umountComponent()}propsValueChanged(){this.umountComponent(),this._umountComponentCallback||(this._umountComponentCallback=this.mountComponent(this.mountElement,this.resolvedComponent,this.componentProps))}get componentProps(){return this.propsValue}get mountElement(){return this.hasMountTarget?this.mountTarget:this.element}get resolvedComponent(){return this.
|
1
|
+
import{Controller as t,Application as o}from"@hotwired/stimulus";class n extends t{constructor(){super(...arguments),this.skipPropsChangeCallback=!1}connect(){this._umountComponentCallback||(this._umountComponentCallback=this.mountComponent(this.mountElement,this.resolvedComponent,this.componentProps))}disconnect(){this.umountComponent()}propsValueChanged(){this.skipPropsChangeCallback?this.skipPropsChangeCallback=!1:(this.umountComponent(),this._umountComponentCallback||(this._umountComponentCallback=this.mountComponent(this.mountElement,this.resolvedComponent,this.componentProps)))}get componentProps(){return this.propsValue}get mountElement(){return this.hasMountTarget?this.mountTarget:this.element}get resolvedComponent(){return this.resolveMounted(this.componentValue).component}get resolvedPlugin(){return this.resolveMounted(this.componentValue).plugin}umountComponent(){this._umountComponentCallback&&this._umountComponentCallback(),this._umountComponentCallback=void 0}mountComponent(t,o,n){return this.resolvedPlugin.mountComponent({el:t,Component:o,props:n})}resolveMounted(t){return this.application.turboMount.resolve(t)}setComponentProps(t){this.skipPropsChangeCallback=!0,this.propsValue=t}}n.values={props:Object,component:String},n.targets=["mount"];class e{constructor(t={}){this.components=new Map,this.application=this.findOrStartApplication(t.application),this.application.turboMount=this,this.application.register("turbo-mount",n),document.addEventListener("turbo:before-morph-element",(t=>{var o;const n=t,{target:e,detail:s}=n;(null===(o=e.getAttribute("data-controller"))||void 0===o?void 0:o.includes("turbo-mount"))&&(e.setAttribute("data-turbo-mount-props-value",s.newElement.getAttribute("data-turbo-mount-props-value")||"{}"),t.preventDefault())}))}register(t,o,e,s){if(s||(s=n),this.components.has(o))throw new Error(`Component '${o}' is already registered.`);if(this.components.set(o,{component:e,plugin:t}),s){const t=`turbo-mount-${r=o,r.replace(/([a-z])([A-Z])/g,"$1-$2").toLowerCase()}`;this.application.register(t,s)}var r}resolve(t){const o=this.components.get(t);if(!o)throw new Error(`Unknown component: ${t}`);return o}findOrStartApplication(t){let n=t||window.Stimulus;return n||(n=o.start(),window.Stimulus=n),n}}function s(t){return(o,n,e,s)=>{o.register(t,n,e,s)}}export{e as TurboMount,n as TurboMountController,s as buildRegisterFunction};
|
2
2
|
//# sourceMappingURL=turbo-mount.min.js.map
|
@@ -1 +1 @@
|
|
1
|
-
{"version":3,"file":"turbo-mount.min.js","sources":["../src/turbo-mount-controller.ts","../src/turbo-mount.ts","../src/helpers.ts"],"sourcesContent":["import { Controller } from \"@hotwired/stimulus\";\nimport { ApplicationWithTurboMount } from \"./turbo-mount\";\n\nexport
|
1
|
+
{"version":3,"file":"turbo-mount.min.js","sources":["../src/turbo-mount-controller.ts","../src/turbo-mount.ts","../src/helpers.ts"],"sourcesContent":["import { Controller } from \"@hotwired/stimulus\";\nimport { ApplicationWithTurboMount } from \"./turbo-mount\";\n\nexport class TurboMountController extends Controller {\n static values = {\n props: Object,\n component: String,\n };\n static targets = [\"mount\"];\n\n private skipPropsChangeCallback = false;\n\n declare propsValue: object;\n declare componentValue: string;\n declare readonly hasMountTarget: boolean;\n declare readonly mountTarget: Element;\n\n _umountComponentCallback?: () => void;\n\n connect() {\n this._umountComponentCallback ||= this.mountComponent(\n this.mountElement,\n this.resolvedComponent,\n this.componentProps,\n );\n }\n\n disconnect() {\n this.umountComponent();\n }\n\n propsValueChanged() {\n // Prevent re-mounting the component if the props are being set by the component itself\n if (this.skipPropsChangeCallback) {\n this.skipPropsChangeCallback = false;\n return;\n }\n\n this.umountComponent();\n this._umountComponentCallback ||= this.mountComponent(\n this.mountElement,\n this.resolvedComponent,\n this.componentProps,\n );\n }\n\n get componentProps() {\n return this.propsValue;\n }\n\n get mountElement() {\n return this.hasMountTarget ? this.mountTarget : this.element;\n }\n\n get resolvedComponent() {\n return this.resolveMounted(this.componentValue).component;\n }\n\n get resolvedPlugin() {\n return this.resolveMounted(this.componentValue).plugin;\n }\n\n umountComponent() {\n this._umountComponentCallback && this._umountComponentCallback();\n this._umountComponentCallback = undefined;\n }\n\n mountComponent(el: Element, Component: unknown, props: object) {\n return this.resolvedPlugin.mountComponent({ el, Component, props });\n }\n\n resolveMounted(component: string) {\n const app = this.application as ApplicationWithTurboMount;\n return app.turboMount.resolve(component);\n }\n\n setComponentProps(props: object) {\n this.skipPropsChangeCallback = true;\n this.propsValue = props;\n }\n}\n","import { Application, ControllerConstructor } from \"@hotwired/stimulus\";\n\nimport { camelToKebabCase } from \"./helpers\";\nimport { TurboMountController } from \"./turbo-mount-controller\";\n\ndeclare global {\n interface Window {\n Stimulus?: Application;\n }\n}\n\nexport interface ApplicationWithTurboMount extends Application {\n turboMount: TurboMount;\n}\n\nexport type MountComponentProps<T> = {\n el: Element;\n Component: T;\n props: object;\n};\n\nexport type Plugin<T> = {\n mountComponent: (props: MountComponentProps<T>) => () => void;\n};\n\nexport type TurboMountProps = {\n application?: Application;\n};\n\ntype TurboMountComponents<T> = Map<string, { component: T; plugin: Plugin<T> }>;\n\ninterface TurboMorphEvent extends CustomEvent {\n target: Element;\n detail: {\n newElement: Element;\n };\n}\n\nexport class TurboMount {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n components: TurboMountComponents<any>;\n application: ApplicationWithTurboMount;\n\n constructor(props: TurboMountProps = {}) {\n this.components = new Map();\n this.application = this.findOrStartApplication(props.application);\n this.application.turboMount = this;\n this.application.register(\"turbo-mount\", TurboMountController);\n\n document.addEventListener(\"turbo:before-morph-element\", (event) => {\n const turboMorphEvent = event as unknown as TurboMorphEvent;\n const { target, detail } = turboMorphEvent;\n\n if (target.getAttribute(\"data-controller\")?.includes(\"turbo-mount\")) {\n target.setAttribute(\n \"data-turbo-mount-props-value\",\n detail.newElement.getAttribute(\"data-turbo-mount-props-value\") ||\n \"{}\",\n );\n event.preventDefault();\n }\n });\n }\n\n register<T>(\n plugin: Plugin<T>,\n name: string,\n component: T,\n controller?: ControllerConstructor,\n ) {\n controller ||= TurboMountController;\n if (this.components.has(name)) {\n throw new Error(`Component '${name}' is already registered.`);\n }\n this.components.set(name, { component, plugin });\n\n if (controller) {\n const controllerName = `turbo-mount-${camelToKebabCase(name)}`;\n this.application.register(controllerName, controller);\n }\n }\n\n resolve(name: string) {\n const component = this.components.get(name);\n if (!component) {\n throw new Error(`Unknown component: ${name}`);\n }\n return component;\n }\n\n private findOrStartApplication(hydratedApp?: Application) {\n let application = hydratedApp || window.Stimulus;\n\n if (!application) {\n application = Application.start();\n window.Stimulus = application;\n }\n return application as ApplicationWithTurboMount;\n }\n}\n\nexport function buildRegisterFunction<T>(plugin: Plugin<T>) {\n return (\n turboMount: TurboMount,\n name: string,\n component: T,\n controller?: ControllerConstructor,\n ) => {\n turboMount.register(plugin, name, component, controller);\n };\n}\n","export const camelToKebabCase = (str: string) => {\n return str.replace(/([a-z])([A-Z])/g, \"$1-$2\").toLowerCase();\n};\n"],"names":["TurboMountController","Controller","constructor","this","skipPropsChangeCallback","connect","_umountComponentCallback","mountComponent","mountElement","resolvedComponent","componentProps","disconnect","umountComponent","propsValueChanged","propsValue","hasMountTarget","mountTarget","element","resolveMounted","componentValue","component","resolvedPlugin","plugin","undefined","el","Component","props","application","turboMount","resolve","setComponentProps","values","Object","String","targets","TurboMount","components","Map","findOrStartApplication","register","document","addEventListener","event","turboMorphEvent","target","detail","_a","getAttribute","includes","setAttribute","newElement","preventDefault","name","controller","has","Error","set","controllerName","str","replace","toLowerCase","get","hydratedApp","window","Stimulus","Application","start","buildRegisterFunction"],"mappings":"iEAGM,MAAOA,UAA6BC,EAA1C,WAAAC,uBAOUC,KAAuBC,yBAAG,CAsEnC,CA7DC,OAAAC,GACEF,KAAKG,2BAALH,KAAKG,yBAA6BH,KAAKI,eACrCJ,KAAKK,aACLL,KAAKM,kBACLN,KAAKO,gBAER,CAED,UAAAC,GACER,KAAKS,iBACN,CAED,iBAAAC,GAEMV,KAAKC,wBACPD,KAAKC,yBAA0B,GAIjCD,KAAKS,kBACLT,KAAKG,2BAALH,KAAKG,yBAA6BH,KAAKI,eACrCJ,KAAKK,aACLL,KAAKM,kBACLN,KAAKO,iBAER,CAED,kBAAIA,GACF,OAAOP,KAAKW,UACb,CAED,gBAAIN,GACF,OAAOL,KAAKY,eAAiBZ,KAAKa,YAAcb,KAAKc,OACtD,CAED,qBAAIR,GACF,OAAON,KAAKe,eAAef,KAAKgB,gBAAgBC,SACjD,CAED,kBAAIC,GACF,OAAOlB,KAAKe,eAAef,KAAKgB,gBAAgBG,MACjD,CAED,eAAAV,GACET,KAAKG,0BAA4BH,KAAKG,2BACtCH,KAAKG,8BAA2BiB,CACjC,CAED,cAAAhB,CAAeiB,EAAaC,EAAoBC,GAC9C,OAAOvB,KAAKkB,eAAed,eAAe,CAAEiB,KAAIC,YAAWC,SAC5D,CAED,cAAAR,CAAeE,GAEb,OADYjB,KAAKwB,YACNC,WAAWC,QAAQT,EAC/B,CAED,iBAAAU,CAAkBJ,GAChBvB,KAAKC,yBAA0B,EAC/BD,KAAKW,WAAaY,CACnB,EA3EM1B,EAAA+B,OAAS,CACdL,MAAOM,OACPZ,UAAWa,QAENjC,EAAAkC,QAAU,CAAC,eC8BPC,EAKX,WAAAjC,CAAYwB,EAAyB,IACnCvB,KAAKiC,WAAa,IAAIC,IACtBlC,KAAKwB,YAAcxB,KAAKmC,uBAAuBZ,EAAMC,aACrDxB,KAAKwB,YAAYC,WAAazB,KAC9BA,KAAKwB,YAAYY,SAAS,cAAevC,GAEzCwC,SAASC,iBAAiB,8BAA+BC,UACvD,MAAMC,EAAkBD,GAClBE,OAAEA,EAAMC,OAAEA,GAAWF,GAEe,QAAtCG,EAAAF,EAAOG,aAAa,0BAAkB,IAAAD,OAAA,EAAAA,EAAEE,SAAS,kBACnDJ,EAAOK,aACL,+BACAJ,EAAOK,WAAWH,aAAa,iCAC7B,MAEJL,EAAMS,iBACP,GAEJ,CAED,QAAAZ,CACEjB,EACA8B,EACAhC,EACAiC,GAGA,GADAA,IAAAA,EAAerD,GACXG,KAAKiC,WAAWkB,IAAIF,GACtB,MAAM,IAAIG,MAAM,cAAcH,6BAIhC,GAFAjD,KAAKiC,WAAWoB,IAAIJ,EAAM,CAAEhC,YAAWE,WAEnC+B,EAAY,CACd,MAAMI,EAAiB,eC7EIC,ED6E4BN,EC5EpDM,EAAIC,QAAQ,kBAAmB,SAASC,gBD6E3CzD,KAAKwB,YAAYY,SAASkB,EAAgBJ,EAC3C,CC/E2B,IAACK,CDgF9B,CAED,OAAA7B,CAAQuB,GACN,MAAMhC,EAAYjB,KAAKiC,WAAWyB,IAAIT,GACtC,IAAKhC,EACH,MAAM,IAAImC,MAAM,sBAAsBH,KAExC,OAAOhC,CACR,CAEO,sBAAAkB,CAAuBwB,GAC7B,IAAInC,EAAcmC,GAAeC,OAAOC,SAMxC,OAJKrC,IACHA,EAAcsC,EAAYC,QAC1BH,OAAOC,SAAWrC,GAEbA,CACR,EAGG,SAAUwC,EAAyB7C,GACvC,MAAO,CACLM,EACAwB,EACAhC,EACAiC,KAEAzB,EAAWW,SAASjB,EAAQ8B,EAAMhC,EAAWiC,EAAW,CAE5D"}
|
@@ -0,0 +1,18 @@
|
|
1
|
+
import { TurboMount } from "turbo-mount";
|
2
|
+
import { registerComponent } from "turbo-mount/<%= framework %>";
|
3
|
+
|
4
|
+
const turboMount = new TurboMount();
|
5
|
+
|
6
|
+
// to register a component use:
|
7
|
+
// registerComponent(turboMount, "Hello", Hello); // where Hello is the imported the component
|
8
|
+
|
9
|
+
// to override the default controller use:
|
10
|
+
// registerComponent(turboMount, "Hello", Hello, HelloController); // where HelloController is a Stimulus controller extended from TurboMountController
|
11
|
+
<%- if vite? -%>
|
12
|
+
|
13
|
+
// If you want to automatically register components use:
|
14
|
+
// import { registerComponents } from "turbo-mount/registerComponents/<%= framework %>";
|
15
|
+
// const controllers = import.meta.glob("/controllers/**/*_controller.js", { eager: true });
|
16
|
+
// const components = import.meta.glob("/components/**/*.jsx", { eager: true });
|
17
|
+
// registerComponents({ turboMount, components, controllers });
|
18
|
+
<%- end -%>
|
@@ -0,0 +1,112 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module TurboMount
|
4
|
+
module Generators
|
5
|
+
class InstallGenerator < Rails::Generators::Base
|
6
|
+
FRAMEWORKS = {
|
7
|
+
"react" => {
|
8
|
+
pins: "react react-dom react-dom/client",
|
9
|
+
npm_packages: "react react-dom",
|
10
|
+
vite_plugin: "@vitejs/plugin-react"
|
11
|
+
},
|
12
|
+
"vue" => {
|
13
|
+
pins: "vue",
|
14
|
+
npm_packages: "vue",
|
15
|
+
vite_plugin: "@vitejs/plugin-vue"
|
16
|
+
},
|
17
|
+
"svelte" => {
|
18
|
+
pins: "svelte",
|
19
|
+
npm_packages: "svelte",
|
20
|
+
vite_plugin: "@sveltejs/vite-plugin-svelte"
|
21
|
+
}
|
22
|
+
}.freeze
|
23
|
+
|
24
|
+
source_root File.expand_path("install", __dir__)
|
25
|
+
|
26
|
+
def install
|
27
|
+
say "Installing Turbo Mount"
|
28
|
+
|
29
|
+
if build_tool.nil?
|
30
|
+
say "Could not find a package.json or config/importmap.rb file to add the turbo-mount dependency to, please add it manually.", :red
|
31
|
+
exit!
|
32
|
+
end
|
33
|
+
|
34
|
+
if importmap?
|
35
|
+
install_importmap
|
36
|
+
else
|
37
|
+
install_nodejs
|
38
|
+
end
|
39
|
+
|
40
|
+
say "Turbo Mount successfully installed", :green
|
41
|
+
end
|
42
|
+
|
43
|
+
private
|
44
|
+
|
45
|
+
def install_nodejs
|
46
|
+
case build_tool
|
47
|
+
when "npm"
|
48
|
+
run "npm install turbo-mount #{FRAMEWORKS[framework][:npm_packages]}"
|
49
|
+
when "yarn"
|
50
|
+
run "yarn add turbo-mount #{FRAMEWORKS[framework][:npm_packages]}"
|
51
|
+
when "bun"
|
52
|
+
run "bun add turbo-mount #{FRAMEWORKS[framework][:npm_packages]}"
|
53
|
+
end
|
54
|
+
|
55
|
+
say "Creating Turbo Mount initializer"
|
56
|
+
template "turbo-mount.js", File.join("app/javascript/turbo-mount.js")
|
57
|
+
append_to_file "app/javascript/entrypoints/application.js", %(import "./turbo-mount"\n)
|
58
|
+
warn_about_vite_plugin if vite?
|
59
|
+
end
|
60
|
+
|
61
|
+
def install_importmap
|
62
|
+
say "Creating Turbo Mount initializer"
|
63
|
+
template "turbo-mount.js", File.join("app/javascript/turbo-mount-initializer.js")
|
64
|
+
append_to_file "app/javascript/application.js", %(import "turbo-mount-initializer"\n)
|
65
|
+
|
66
|
+
say "Pinning Turbo Mount to the importmap"
|
67
|
+
append_to_file "config/importmap.rb", %(pin "turbo-mount", to: "turbo-mount.min.js"\n)
|
68
|
+
append_to_file "config/importmap.rb", %(pin "turbo-mount/#{framework}", to: "turbo-mount/#{framework}.min.js"\n)
|
69
|
+
append_to_file "config/importmap.rb", %(pin "turbo-mount-initializer"\n)
|
70
|
+
|
71
|
+
say "Pinning framework dependencies to the importmap"
|
72
|
+
run "bin/importmap pin #{FRAMEWORKS[framework][:pins]}"
|
73
|
+
end
|
74
|
+
|
75
|
+
def vite?
|
76
|
+
Dir.glob(Rails.root.join("vite.config.*")).any?
|
77
|
+
end
|
78
|
+
|
79
|
+
def importmap?
|
80
|
+
build_tool == "importmap"
|
81
|
+
end
|
82
|
+
|
83
|
+
def warn_about_vite_plugin
|
84
|
+
say "Make sure to install and add #{FRAMEWORKS[framework][:vite_plugin]} to your Vite config", :yellow
|
85
|
+
end
|
86
|
+
|
87
|
+
def build_tool
|
88
|
+
return @build_tool if defined?(@build_tool)
|
89
|
+
|
90
|
+
@build_tool = detect_build_tool
|
91
|
+
end
|
92
|
+
|
93
|
+
def detect_build_tool
|
94
|
+
if Rails.root.join("package.json").exist?
|
95
|
+
if Rails.root.join("package-lock.json").exist?
|
96
|
+
"npm"
|
97
|
+
elsif Rails.root.join("bun.config.js").exist?
|
98
|
+
"bun"
|
99
|
+
else
|
100
|
+
"yarn"
|
101
|
+
end
|
102
|
+
elsif Rails.root.join("config/importmap.rb").exist?
|
103
|
+
"importmap"
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
107
|
+
def framework
|
108
|
+
@framework ||= ask("What framework do you want to use with Turbo Mount?", limited_to: FRAMEWORKS.keys, default: "react")
|
109
|
+
end
|
110
|
+
end
|
111
|
+
end
|
112
|
+
end
|
data/lib/turbo/mount/helpers.rb
CHANGED
@@ -3,10 +3,10 @@
|
|
3
3
|
module Turbo
|
4
4
|
module Mount
|
5
5
|
module Helpers
|
6
|
-
def
|
6
|
+
def turbo_mount(component_name, props: {}, tag: "div", **attrs, &block)
|
7
7
|
raise TypeError, "Component name expected" unless component_name.is_a? String
|
8
8
|
|
9
|
-
controller_name = "turbo-mount-#{
|
9
|
+
controller_name = "turbo-mount-#{component_name.underscore.dasherize}"
|
10
10
|
attrs["data-controller"] = controller_name
|
11
11
|
prefix = "data-#{controller_name}"
|
12
12
|
attrs["#{prefix}-component-value"] = component_name
|
@@ -16,18 +16,7 @@ module Turbo
|
|
16
16
|
|
17
17
|
content_tag(tag, nil, attrs) { capture(controller_name, &block) }
|
18
18
|
end
|
19
|
-
|
20
|
-
def turbo_mount_react_component(component_name, **attrs, &block)
|
21
|
-
turbo_mount_component(component_name, framework: "react", **attrs, &block)
|
22
|
-
end
|
23
|
-
|
24
|
-
def turbo_mount_svelte_component(component_name, **attrs, &block)
|
25
|
-
turbo_mount_component(component_name, framework: "svelte", **attrs, &block)
|
26
|
-
end
|
27
|
-
|
28
|
-
def turbo_mount_vue_component(component_name, **attrs, &block)
|
29
|
-
turbo_mount_component(component_name, framework: "vue", **attrs, &block)
|
30
|
-
end
|
19
|
+
alias_method :turbo_mount_component, :turbo_mount
|
31
20
|
end
|
32
21
|
end
|
33
22
|
end
|
data/lib/turbo/mount/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: turbo-mount
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.3.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Svyatoslav Kryukov
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2024-05-
|
11
|
+
date: 2024-05-31 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: railties
|
@@ -47,6 +47,8 @@ files:
|
|
47
47
|
- app/assets/javascripts/turbo-mount/vue.js
|
48
48
|
- app/assets/javascripts/turbo-mount/vue.min.js
|
49
49
|
- app/assets/javascripts/turbo-mount/vue.min.js.map
|
50
|
+
- lib/generators/turbo_mount/install/turbo-mount.js.tt
|
51
|
+
- lib/generators/turbo_mount/install_generator.rb
|
50
52
|
- lib/turbo/mount.rb
|
51
53
|
- lib/turbo/mount/engine.rb
|
52
54
|
- lib/turbo/mount/helpers.rb
|