turbo-mount 0.2.0 → 0.2.3
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +18 -1
- data/README.md +100 -18
- data/app/assets/javascripts/turbo-mount/react.js +11 -4
- 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 +11 -4
- 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 +11 -4
- 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 +21 -11
- data/app/assets/javascripts/turbo-mount.min.js +1 -1
- data/app/assets/javascripts/turbo-mount.min.js.map +1 -1
- data/lib/turbo/mount/helpers.rb +13 -10
- data/lib/turbo/mount/version.rb +1 -1
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: '0318ba2497956b4a56bc035a5a39e617bf0b171b039823fd61fe131294ca5815'
|
4
|
+
data.tar.gz: 6a078a433b9766915496ac9d86d9df81782eec209c495ccefcb978643c810a39
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 75dd9c6f8b0760791c40d3db5b07cf95056bc199550d95c5a86cec1686a8f11eb0594ad7e1d4d4c015867289371f18e2b1cc7f1ccb6738e24b8342a42e7b8f1c
|
7
|
+
data.tar.gz: 1ac86acfbb7d0e5c01e61c791e6ba058d78ae01092bdd1dc5cdd0059a5309922888a59cd0afad63541c2c517c478f159d351ef2e0da326ddddf1b48d6c9de534
|
data/CHANGELOG.md
CHANGED
@@ -7,6 +7,21 @@ and this project adheres to [Semantic Versioning].
|
|
7
7
|
|
8
8
|
## [Unreleased]
|
9
9
|
|
10
|
+
## [0.2.3] - 2024-05-12
|
11
|
+
|
12
|
+
### Added
|
13
|
+
|
14
|
+
- Add a mount target to the base controller. ([@skryukov])
|
15
|
+
- Add `registerComponents` helper for vite. ([@skryukov])
|
16
|
+
- Allow to omit the `application` property in the constructor. ([@skryukov])
|
17
|
+
`TurboMount` will try to find the application in the `window.Stimulus` and will initialize new one if not found.
|
18
|
+
|
19
|
+
## [0.2.2] - 2024-05-09
|
20
|
+
|
21
|
+
### Fixed
|
22
|
+
|
23
|
+
- Export plugins. ([@skryukov])
|
24
|
+
|
10
25
|
## [0.2.0] - 2024-05-09
|
11
26
|
|
12
27
|
### Added
|
@@ -21,7 +36,9 @@ and this project adheres to [Semantic Versioning].
|
|
21
36
|
|
22
37
|
[@skryukov]: https://github.com/skryukov
|
23
38
|
|
24
|
-
[Unreleased]: https://github.com/skryukov/turbo-mount/compare/v0.2.
|
39
|
+
[Unreleased]: https://github.com/skryukov/turbo-mount/compare/v0.2.3...HEAD
|
40
|
+
[0.2.3]: https://github.com/skryukov/turbo-mount/commits/v0.2.3
|
41
|
+
[0.2.2]: https://github.com/skryukov/turbo-mount/commits/v0.2.2
|
25
42
|
[0.2.0]: https://github.com/skryukov/turbo-mount/commits/v0.2.0
|
26
43
|
[0.1.0]: https://github.com/skryukov/turbo-mount/commits/v0.1.0
|
27
44
|
|
data/README.md
CHANGED
@@ -6,35 +6,72 @@
|
|
6
6
|
|
7
7
|
## Installation
|
8
8
|
|
9
|
-
|
9
|
+
Add the following line to your Gemfile:
|
10
10
|
|
11
|
-
|
11
|
+
```ruby
|
12
|
+
gem "turbo-mount"
|
13
|
+
```
|
12
14
|
|
13
|
-
|
15
|
+
For projects utilizing build tools such as [Vite](http://vite-ruby.netlify.app), also install `turbo-mount` package:
|
14
16
|
|
15
|
-
|
17
|
+
```bash
|
18
|
+
npm install turbo-mount
|
19
|
+
# or with yarn
|
20
|
+
yarn add turbo-mount
|
21
|
+
```
|
16
22
|
|
17
23
|
## Usage
|
18
24
|
|
19
|
-
|
25
|
+
### Initialization
|
26
|
+
|
27
|
+
To begin using `TurboMount`, start by initializing the library and registering the components you intend to use. Below are the steps to set up `TurboMount` with different configurations.
|
28
|
+
|
29
|
+
#### Standard Initialization
|
30
|
+
|
31
|
+
Import the necessary modules and initialize ```TurboMount``` with your application and the desired plugin. Here's how to set it up with a React plugin:
|
32
|
+
|
33
|
+
```js
|
34
|
+
import { Application } from "@hotwired/stimulus";
|
35
|
+
import { TurboMount } from "turbo-mount";
|
36
|
+
import plugin from "turbo-mount/react";
|
37
|
+
import { SketchPicker } from 'react-color';
|
38
|
+
|
39
|
+
const application = Application.start();
|
40
|
+
const turboMount = new TurboMount({ application, plugin });
|
41
|
+
|
42
|
+
turboMount.register('SketchPicker', SketchPicker);
|
43
|
+
```
|
44
|
+
|
45
|
+
#### Simplified Initialization
|
46
|
+
|
47
|
+
If you prefer not to specify the `application` explicitly, `TurboMount` can automatically detect or initialize it. This approach uses the `window.Stimulus` if available; otherwise, it initializes a new Stimulus application:
|
20
48
|
|
21
49
|
```js
|
22
|
-
import {
|
50
|
+
import { TurboMount } from "turbo-mount";
|
51
|
+
import plugin from "turbo-mount/react";
|
52
|
+
import { SketchPicker } from 'react-color';
|
53
|
+
|
54
|
+
const turboMount = new TurboMount({ plugin });
|
55
|
+
|
56
|
+
turboMount.register('SketchPicker', SketchPicker);
|
57
|
+
```
|
23
58
|
|
24
|
-
|
59
|
+
#### Plugin-Specific Initialization
|
25
60
|
|
26
|
-
import
|
27
|
-
import plugin from "turbo-mount/react"
|
61
|
+
For a more streamlined setup, you can directly import a specialized version of `TurboMount`:
|
28
62
|
|
29
|
-
|
30
|
-
|
63
|
+
```js
|
64
|
+
import { TurboMountReact } from "turbo-mount/react";
|
65
|
+
import { SketchPicker } from 'react-color';
|
66
|
+
|
67
|
+
const turboMount = new TurboMountReact();
|
31
68
|
|
32
|
-
// Register the components you want to use
|
33
|
-
import { SketchPicker } from 'react-color'
|
34
69
|
turboMount.register('SketchPicker', SketchPicker);
|
35
70
|
```
|
36
71
|
|
37
|
-
|
72
|
+
### View Helpers
|
73
|
+
|
74
|
+
Use the following helpers to mount components in your views:
|
38
75
|
|
39
76
|
```erb
|
40
77
|
<%= turbo_mount_component("SketchPicker", framework: "react", props: {color: "#034"}) %>
|
@@ -44,11 +81,21 @@ Now you can use view helpers to mount the components:
|
|
44
81
|
<%= turbo_mount_react_component("SketchPicker", props: {color: "#430"}) %>
|
45
82
|
```
|
46
83
|
|
47
|
-
|
84
|
+
### Supported Frameworks
|
48
85
|
|
49
|
-
|
50
|
-
|
86
|
+
`TurboMount` supports the following frameworks:
|
87
|
+
|
88
|
+
- React `"turbo-mount/react"`
|
89
|
+
- Vue `"turbo-mount/vue"`
|
90
|
+
- Svelte `"turbo-mount/svelte"`
|
91
|
+
|
92
|
+
It's possible to add support for other frameworks by creating custom controller class extending `TurboMountController` and providing a plugin. See included plugins for examples.
|
93
|
+
|
94
|
+
### Custom Controllers
|
95
|
+
|
96
|
+
To customize component behavior or pass functions as props, create a custom controller:
|
51
97
|
|
98
|
+
```js
|
52
99
|
import { TurboMountReactController } from "turbo-mount"
|
53
100
|
|
54
101
|
export default class extends TurboMountReactController {
|
@@ -68,7 +115,42 @@ export default class extends TurboMountReactController {
|
|
68
115
|
Then pass this controller the register method:
|
69
116
|
|
70
117
|
```js
|
71
|
-
|
118
|
+
import SketchController from "controllers/turbo_mount/sketch_picker_controller"
|
119
|
+
|
120
|
+
turboMount.register('SketchPicker', SketchPicker, SketchController);
|
121
|
+
```
|
122
|
+
|
123
|
+
### Vite Integration
|
124
|
+
|
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:
|
126
|
+
|
127
|
+
```js
|
128
|
+
import { TurboMount } from "turbo-mount/react";
|
129
|
+
import { registerComponents } from "turbo-mount/vite";
|
130
|
+
|
131
|
+
const controllers = import.meta.glob("./**/*_controller.js", { eager: true });
|
132
|
+
const components = import.meta.glob(`/components/**/*.jsx`, { eager: true });
|
133
|
+
|
134
|
+
const turboMount = new TurboMount();
|
135
|
+
registerComponents({ turboMount, components, controllers });
|
136
|
+
```
|
137
|
+
|
138
|
+
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
|
+
- `controllers/turbo-mount/${controllerName}`
|
143
|
+
- `controllers/turbo-mount-${controllerName}`
|
144
|
+
|
145
|
+
### Mount target
|
146
|
+
|
147
|
+
To specify a non-root mount target, use the `data-<%= controller_name %>-target="mount"` attribute:
|
148
|
+
|
149
|
+
```erb
|
150
|
+
<%= turbo_mount_react_component("SketchPicker", props: {color: "#430"}) do |controller_name| %>
|
151
|
+
<h3>Color picker</h3>
|
152
|
+
<div data-<%= controller_name %>-target="mount"></div>
|
153
|
+
<% end %>
|
72
154
|
```
|
73
155
|
|
74
156
|
## Development
|
@@ -1,6 +1,6 @@
|
|
1
|
+
import { TurboMountController, TurboMount } from 'turbo-mount';
|
1
2
|
import { createElement } from 'react';
|
2
3
|
import { createRoot } from 'react-dom/client';
|
3
|
-
import { TurboMountController } from 'turbo-mount';
|
4
4
|
|
5
5
|
class TurboMountReactController extends TurboMountController {
|
6
6
|
constructor() {
|
@@ -10,13 +10,20 @@ class TurboMountReactController extends TurboMountController {
|
|
10
10
|
mountComponent(el, Component, props) {
|
11
11
|
const root = createRoot(el);
|
12
12
|
root.render(createElement(Component, props));
|
13
|
-
return () => {
|
13
|
+
return () => {
|
14
|
+
root.unmount();
|
15
|
+
};
|
14
16
|
}
|
15
17
|
}
|
16
18
|
|
17
19
|
const plugin = {
|
18
20
|
framework: "react",
|
19
|
-
controller: TurboMountReactController
|
21
|
+
controller: TurboMountReactController,
|
20
22
|
};
|
23
|
+
class TurboMountReact extends TurboMount {
|
24
|
+
constructor(props) {
|
25
|
+
super(Object.assign(Object.assign({}, props), { plugin }));
|
26
|
+
}
|
27
|
+
}
|
21
28
|
|
22
|
-
export { plugin as default };
|
29
|
+
export { TurboMountReact as TurboMount, TurboMountReact, plugin as default };
|
@@ -1,2 +1,2 @@
|
|
1
|
-
import{
|
1
|
+
import{TurboMountController as r,TurboMount as t}from"turbo-mount";import{createElement as o}from"react";import{createRoot as e}from"react-dom/client";const n={framework:"react",controller:class extends r{constructor(){super(...arguments),this.framework="react"}mountComponent(r,t,n){const s=e(r);return s.render(o(t,n)),()=>{s.unmount()}}}};class s extends t{constructor(r){super(Object.assign(Object.assign({},r),{plugin:n}))}}export{s as TurboMount,s as TurboMountReact,n as default};
|
2
2
|
//# sourceMappingURL=react.min.js.map
|
@@ -1 +1 @@
|
|
1
|
-
{"version":3,"file":"react.min.js","sources":["../../src/plugins/react/index.ts","../../src/plugins/react/turbo-mount-react-controller.ts"],"sourcesContent":["import {Plugin} from \"turbo-mount\";\n\nimport {TurboMountReactController} from \"./turbo-mount-react-controller\";\n\nconst plugin: Plugin = {\n
|
1
|
+
{"version":3,"file":"react.min.js","sources":["../../src/plugins/react/index.ts","../../src/plugins/react/turbo-mount-react-controller.ts"],"sourcesContent":["import { Plugin, TurboMount, TurboMountProps } from \"turbo-mount\";\n\nimport { TurboMountReactController } from \"./turbo-mount-react-controller\";\n\nconst plugin: Plugin = {\n framework: \"react\",\n controller: TurboMountReactController,\n};\n\nexport class TurboMountReact<T> extends TurboMount<T> {\n constructor(props: Omit<TurboMountProps, \"plugin\">) {\n super({ ...props, plugin });\n }\n}\n\nexport { TurboMountReact as TurboMount };\n\nexport default plugin;\n","import { ComponentType, createElement } from \"react\";\nimport { createRoot } from \"react-dom/client\";\nimport { TurboMountController } from \"turbo-mount\";\n\nexport class TurboMountReactController extends TurboMountController<ComponentType> {\n framework = \"react\";\n\n mountComponent(el: Element, Component: ComponentType, props: object) {\n const root = createRoot(el);\n root.render(createElement(Component, props));\n\n return () => {\n root.unmount();\n };\n }\n}\n"],"names":["plugin","framework","controller","TurboMountController","constructor","this","mountComponent","el","Component","props","root","createRoot","render","createElement","unmount","TurboMountReact","TurboMount","super","Object","assign"],"mappings":"uJAIA,MAAMA,EAAiB,CACrBC,UAAW,QACXC,WCFI,cAAyCC,EAA/C,WAAAC,uBACEC,KAASJ,UAAG,OAUb,CARC,cAAAK,CAAeC,EAAaC,EAA0BC,GACpD,MAAMC,EAAOC,EAAWJ,GAGxB,OAFAG,EAAKE,OAAOC,EAAcL,EAAWC,IAE9B,KACLC,EAAKI,SAAS,CAEjB,IDLG,MAAOC,UAA2BC,EACtC,WAAAZ,CAAYK,GACVQ,MAAWC,OAAAC,OAAAD,OAAAC,OAAA,GAAAV,GAAO,CAAAT,WACnB"}
|
@@ -1,4 +1,4 @@
|
|
1
|
-
import { TurboMountController } from 'turbo-mount';
|
1
|
+
import { TurboMountController, TurboMount } from 'turbo-mount';
|
2
2
|
|
3
3
|
class TurboMountSvelteController extends TurboMountController {
|
4
4
|
constructor() {
|
@@ -7,13 +7,20 @@ class TurboMountSvelteController extends TurboMountController {
|
|
7
7
|
}
|
8
8
|
mountComponent(el, Component, props) {
|
9
9
|
const component = new Component({ target: el, props });
|
10
|
-
return () => {
|
10
|
+
return () => {
|
11
|
+
component.$destroy();
|
12
|
+
};
|
11
13
|
}
|
12
14
|
}
|
13
15
|
|
14
16
|
const plugin = {
|
15
17
|
framework: "svelte",
|
16
|
-
controller: TurboMountSvelteController
|
18
|
+
controller: TurboMountSvelteController,
|
17
19
|
};
|
20
|
+
class TurboMountSvelte extends TurboMount {
|
21
|
+
constructor(props) {
|
22
|
+
super(Object.assign(Object.assign({}, props), { plugin }));
|
23
|
+
}
|
24
|
+
}
|
18
25
|
|
19
|
-
export { plugin as default };
|
26
|
+
export { TurboMountSvelte as TurboMount, TurboMountSvelte, plugin as default };
|
@@ -1,2 +1,2 @@
|
|
1
|
-
import{TurboMountController as t}from"turbo-mount";const
|
1
|
+
import{TurboMountController as t,TurboMount as s}from"turbo-mount";const e={framework:"svelte",controller:class extends t{constructor(){super(...arguments),this.framework="svelte"}mountComponent(t,s,e){const o=new s({target:t,props:e});return()=>{o.$destroy()}}}};class o extends s{constructor(t){super(Object.assign(Object.assign({},t),{plugin:e}))}}export{o as TurboMount,o as TurboMountSvelte,e as default};
|
2
2
|
//# sourceMappingURL=svelte.min.js.map
|
@@ -1 +1 @@
|
|
1
|
-
{"version":3,"file":"svelte.min.js","sources":["../../src/plugins/svelte/index.ts","../../src/plugins/svelte/turbo-mount-svelte-controller.ts"],"sourcesContent":["import {Plugin} from \"turbo-mount\";\n\nimport {TurboMountSvelteController} from \"./turbo-mount-svelte-controller\";\n\nconst plugin: Plugin = {\n
|
1
|
+
{"version":3,"file":"svelte.min.js","sources":["../../src/plugins/svelte/index.ts","../../src/plugins/svelte/turbo-mount-svelte-controller.ts"],"sourcesContent":["import { Plugin, TurboMount, TurboMountProps } from \"turbo-mount\";\n\nimport { TurboMountSvelteController } from \"./turbo-mount-svelte-controller\";\n\nconst plugin: Plugin = {\n framework: \"svelte\",\n controller: TurboMountSvelteController,\n};\n\nexport class TurboMountSvelte<T> extends TurboMount<T> {\n constructor(props: Omit<TurboMountProps, \"plugin\">) {\n super({ ...props, plugin });\n }\n}\n\nexport { TurboMountSvelte as TurboMount };\nexport default plugin;\n","import { ComponentType } from \"svelte\";\nimport { TurboMountController } from \"turbo-mount\";\n\nexport class TurboMountSvelteController extends TurboMountController<ComponentType> {\n framework = \"svelte\";\n\n mountComponent(el: Element, Component: ComponentType, props: object) {\n const component = new Component({ target: el, props });\n\n return () => {\n component.$destroy();\n };\n }\n}\n"],"names":["plugin","framework","controller","TurboMountController","constructor","this","mountComponent","el","Component","props","component","target","$destroy","TurboMountSvelte","TurboMount","super","Object","assign"],"mappings":"mEAIA,MAAMA,EAAiB,CACrBC,UAAW,SACXC,WCHI,cAA0CC,EAAhD,WAAAC,uBACEC,KAASJ,UAAG,QASb,CAPC,cAAAK,CAAeC,EAAaC,EAA0BC,GACpD,MAAMC,EAAY,IAAIF,EAAU,CAAEG,OAAQJ,EAAIE,UAE9C,MAAO,KACLC,EAAUE,UAAU,CAEvB,IDHG,MAAOC,UAA4BC,EACvC,WAAAV,CAAYK,GACVM,MAAWC,OAAAC,OAAAD,OAAAC,OAAA,GAAAR,GAAO,CAAAT,WACnB"}
|
@@ -1,5 +1,5 @@
|
|
1
|
+
import { TurboMountController, TurboMount } from 'turbo-mount';
|
1
2
|
import { createApp } from 'vue';
|
2
|
-
import { TurboMountController } from 'turbo-mount';
|
3
3
|
|
4
4
|
class TurboMountVueController extends TurboMountController {
|
5
5
|
constructor() {
|
@@ -9,13 +9,20 @@ class TurboMountVueController extends TurboMountController {
|
|
9
9
|
mountComponent(el, Component, props) {
|
10
10
|
const app = createApp(Component, props);
|
11
11
|
app.mount(el);
|
12
|
-
return () => {
|
12
|
+
return () => {
|
13
|
+
app.unmount();
|
14
|
+
};
|
13
15
|
}
|
14
16
|
}
|
15
17
|
|
16
18
|
const plugin = {
|
17
19
|
framework: "vue",
|
18
|
-
controller: TurboMountVueController
|
20
|
+
controller: TurboMountVueController,
|
19
21
|
};
|
22
|
+
class TurboMountVue extends TurboMount {
|
23
|
+
constructor(props) {
|
24
|
+
super(Object.assign(Object.assign({}, props), { plugin }));
|
25
|
+
}
|
26
|
+
}
|
20
27
|
|
21
|
-
export { plugin as default };
|
28
|
+
export { TurboMountVue as TurboMount, TurboMountVue, plugin as default };
|
@@ -1,2 +1,2 @@
|
|
1
|
-
import{
|
1
|
+
import{TurboMountController as o,TurboMount as t}from"turbo-mount";import{createApp as r}from"vue";const n={framework:"vue",controller:class extends o{constructor(){super(...arguments),this.framework="vue"}mountComponent(o,t,n){const s=r(t,n);return s.mount(o),()=>{s.unmount()}}}};class s extends t{constructor(o){super(Object.assign(Object.assign({},o),{plugin:n}))}}export{s as TurboMount,s as TurboMountVue,n as default};
|
2
2
|
//# sourceMappingURL=vue.min.js.map
|
@@ -1 +1 @@
|
|
1
|
-
{"version":3,"file":"vue.min.js","sources":["../../src/plugins/vue/index.ts","../../src/plugins/vue/turbo-mount-vue-controller.ts"],"sourcesContent":["import {Plugin} from \"turbo-mount\";\n\nimport {TurboMountVueController} from \"./turbo-mount-vue-controller\";\n\nconst plugin: Plugin = {\n
|
1
|
+
{"version":3,"file":"vue.min.js","sources":["../../src/plugins/vue/index.ts","../../src/plugins/vue/turbo-mount-vue-controller.ts"],"sourcesContent":["import { Plugin, TurboMount, TurboMountProps } from \"turbo-mount\";\n\nimport { TurboMountVueController } from \"./turbo-mount-vue-controller\";\n\nconst plugin: Plugin = {\n framework: \"vue\",\n controller: TurboMountVueController,\n};\n\nexport class TurboMountVue<T> extends TurboMount<T> {\n constructor(props: Omit<TurboMountProps, \"plugin\">) {\n super({ ...props, plugin });\n }\n}\n\nexport { TurboMountVue as TurboMount };\n\nexport default plugin;\n","import { createApp, App } from \"vue\";\nimport { TurboMountController } from \"turbo-mount\";\n\nexport class TurboMountVueController extends TurboMountController<App> {\n framework = \"vue\";\n\n mountComponent(el: Element, Component: App, props: object) {\n const app = createApp(Component, props as Record<string, unknown>);\n app.mount(el);\n\n return () => {\n app.unmount();\n };\n }\n}\n"],"names":["plugin","framework","controller","TurboMountController","constructor","this","mountComponent","el","Component","props","app","createApp","mount","unmount","TurboMountVue","TurboMount","super","Object","assign"],"mappings":"mGAIA,MAAMA,EAAiB,CACrBC,UAAW,MACXC,WCHI,cAAuCC,EAA7C,WAAAC,uBACEC,KAASJ,UAAG,KAUb,CARC,cAAAK,CAAeC,EAAaC,EAAgBC,GAC1C,MAAMC,EAAMC,EAAUH,EAAWC,GAGjC,OAFAC,EAAIE,MAAML,GAEH,KACLG,EAAIG,SAAS,CAEhB,IDJG,MAAOC,UAAyBC,EACpC,WAAAX,CAAYK,GACVO,MAAWC,OAAAC,OAAAD,OAAAC,OAAA,GAAAT,GAAO,CAAAT,WACnB"}
|
@@ -1,4 +1,4 @@
|
|
1
|
-
import { Controller } from '@hotwired/stimulus';
|
1
|
+
import { Controller, Application } from '@hotwired/stimulus';
|
2
2
|
|
3
3
|
class TurboMountController extends Controller {
|
4
4
|
connect() {
|
@@ -15,7 +15,7 @@ class TurboMountController extends Controller {
|
|
15
15
|
return this.propsValue;
|
16
16
|
}
|
17
17
|
get mountElement() {
|
18
|
-
return this.element;
|
18
|
+
return this.hasMountTarget ? this.mountTarget : this.element;
|
19
19
|
}
|
20
20
|
get resolvedComponent() {
|
21
21
|
return this.resolveComponent(this.componentValue);
|
@@ -31,22 +31,35 @@ class TurboMountController extends Controller {
|
|
31
31
|
}
|
32
32
|
TurboMountController.values = {
|
33
33
|
props: Object,
|
34
|
-
component: String
|
34
|
+
component: String,
|
35
|
+
};
|
36
|
+
TurboMountController.targets = ["mount"];
|
37
|
+
|
38
|
+
const camelToKebabCase = (str) => {
|
39
|
+
return str.replace(/([a-z])([A-Z])/g, "$1-$2").toLowerCase();
|
35
40
|
};
|
36
41
|
|
37
42
|
class TurboMount {
|
38
|
-
constructor(
|
43
|
+
constructor({ application, plugin }) {
|
39
44
|
var _a;
|
40
45
|
this.components = new Map();
|
41
|
-
this.application =
|
42
|
-
this.framework =
|
43
|
-
this.baseController =
|
46
|
+
this.application = this.findOrStartApplication(application);
|
47
|
+
this.framework = plugin.framework;
|
48
|
+
this.baseController = plugin.controller;
|
44
49
|
(_a = this.application).turboMount || (_a.turboMount = {});
|
45
50
|
this.application.turboMount[this.framework] = this;
|
46
51
|
if (this.baseController) {
|
47
52
|
this.application.register(`turbo-mount-${this.framework}`, this.baseController);
|
48
53
|
}
|
49
54
|
}
|
55
|
+
findOrStartApplication(hydratedApp) {
|
56
|
+
let application = hydratedApp || window.Stimulus;
|
57
|
+
if (!application) {
|
58
|
+
application = Application.start();
|
59
|
+
window.Stimulus = application;
|
60
|
+
}
|
61
|
+
return application;
|
62
|
+
}
|
50
63
|
register(name, component, controller) {
|
51
64
|
controller || (controller = this.baseController);
|
52
65
|
if (this.components.has(name)) {
|
@@ -54,7 +67,7 @@ class TurboMount {
|
|
54
67
|
}
|
55
68
|
this.components.set(name, component);
|
56
69
|
if (controller) {
|
57
|
-
const controllerName = `turbo-mount-${this.framework}-${
|
70
|
+
const controllerName = `turbo-mount-${this.framework}-${camelToKebabCase(name)}`;
|
58
71
|
this.application.register(controllerName, controller);
|
59
72
|
}
|
60
73
|
}
|
@@ -65,9 +78,6 @@ class TurboMount {
|
|
65
78
|
}
|
66
79
|
return component;
|
67
80
|
}
|
68
|
-
camelToKebabCase(str) {
|
69
|
-
return str.replace(/([a-z])([A-Z])/g, '$1-$2').toLowerCase();
|
70
|
-
}
|
71
81
|
}
|
72
82
|
|
73
83
|
export { TurboMount, TurboMountController };
|
@@ -1,2 +1,2 @@
|
|
1
|
-
import{Controller as t}from"@hotwired/stimulus";class
|
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.resolveComponent(this.componentValue)}umountComponent(){this._umountComponentCallback&&this._umountComponentCallback(),this._umountComponentCallback=void 0}resolveComponent(t){return this.application.turboMount[this.framework].resolve(t)}}n.values={props:Object,component:String},n.targets=["mount"];class e{constructor({application:t,plugin:o}){var n;this.components=new Map,this.application=this.findOrStartApplication(t),this.framework=o.framework,this.baseController=o.controller,(n=this.application).turboMount||(n.turboMount={}),this.application.turboMount[this.framework]=this,this.baseController&&this.application.register(`turbo-mount-${this.framework}`,this.baseController)}findOrStartApplication(t){let n=t||window.Stimulus;return n||(n=o.start(),window.Stimulus=n),n}register(t,o,n){if(n||(n=this.baseController),this.components.has(t))throw new Error(`Component '${t}' is already registered.`);if(this.components.set(t,o),n){const o=`turbo-mount-${this.framework}-${e=t,e.replace(/([a-z])([A-Z])/g,"$1-$2").toLowerCase()}`;this.application.register(o,n)}var e}resolve(t){const o=this.components.get(t);if(!o)throw new Error(`Unknown component: ${t}`);return o}}export{e as TurboMount,n as TurboMountController};
|
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"],"sourcesContent":["import {Controller} from \"@hotwired/stimulus\"
|
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 abstract class TurboMountController<T> extends Controller {\n static values = {\n props: Object,\n component: String,\n };\n static targets = [\"mount\"];\n\n declare readonly propsValue: object;\n declare readonly componentValue: string;\n declare readonly hasMountTarget: boolean;\n declare readonly mountTarget: Element;\n\n abstract framework: string;\n\n abstract mountComponent(el: Element, Component: T, props: object): () => void;\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 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.resolveComponent(this.componentValue);\n }\n\n umountComponent() {\n this._umountComponentCallback && this._umountComponentCallback();\n this._umountComponentCallback = undefined;\n }\n\n resolveComponent(component: string): T {\n const app = this.application as ApplicationWithTurboMount<T>;\n return app.turboMount[this.framework].resolve(component);\n }\n}\n","import { Application, ControllerConstructor } from \"@hotwired/stimulus\";\n\nimport { camelToKebabCase } from \"./helpers\";\n\ndeclare global {\n interface Window {\n Stimulus?: Application;\n }\n}\n\nexport interface ApplicationWithTurboMount<T> extends Application {\n turboMount: { [framework: string]: TurboMount<T> };\n}\n\nexport type Plugin = {\n framework: string;\n controller: ControllerConstructor;\n};\n\nexport type TurboMountProps = {\n application?: Application;\n plugin: Plugin;\n};\n\nexport class TurboMount<T> {\n components: Map<string, T>;\n application: ApplicationWithTurboMount<T>;\n framework: string;\n baseController?: ControllerConstructor;\n\n constructor({ application, plugin }: TurboMountProps) {\n this.components = new Map();\n this.application = this.findOrStartApplication(application);\n this.framework = plugin.framework;\n this.baseController = plugin.controller;\n\n this.application.turboMount ||= {};\n this.application.turboMount[this.framework] = this;\n\n if (this.baseController) {\n this.application.register(\n `turbo-mount-${this.framework}`,\n this.baseController,\n );\n }\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<T>;\n }\n\n register(name: string, component: T, controller?: ControllerConstructor) {\n controller ||= this.baseController;\n if (this.components.has(name)) {\n throw new Error(`Component '${name}' is already registered.`);\n }\n this.components.set(name, component);\n\n if (controller) {\n const controllerName = `turbo-mount-${this.framework}-${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","export const camelToKebabCase = (str: string) => {\n return str.replace(/([a-z])([A-Z])/g, \"$1-$2\").toLowerCase();\n};\n"],"names":["TurboMountController","Controller","connect","this","_umountComponentCallback","mountComponent","mountElement","resolvedComponent","componentProps","disconnect","umountComponent","propsValueChanged","propsValue","hasMountTarget","mountTarget","element","resolveComponent","componentValue","undefined","component","application","turboMount","framework","resolve","values","props","Object","String","targets","TurboMount","constructor","plugin","components","Map","findOrStartApplication","baseController","controller","_a","register","hydratedApp","window","Stimulus","Application","start","name","has","Error","set","controllerName","str","replace","toLowerCase","get"],"mappings":"iEAGM,MAAgBA,UAAgCC,EAkBpD,OAAAC,GACEC,KAAKC,2BAALD,KAAKC,yBAA6BD,KAAKE,eACrCF,KAAKG,aACLH,KAAKI,kBACLJ,KAAKK,gBAER,CAED,UAAAC,GACEN,KAAKO,iBACN,CAED,iBAAAC,GACER,KAAKO,kBACLP,KAAKC,2BAALD,KAAKC,yBAA6BD,KAAKE,eACrCF,KAAKG,aACLH,KAAKI,kBACLJ,KAAKK,gBAER,CAED,kBAAIA,GACF,OAAOL,KAAKS,UACb,CAED,gBAAIN,GACF,OAAOH,KAAKU,eAAiBV,KAAKW,YAAcX,KAAKY,OACtD,CAED,qBAAIR,GACF,OAAOJ,KAAKa,iBAAiBb,KAAKc,eACnC,CAED,eAAAP,GACEP,KAAKC,0BAA4BD,KAAKC,2BACtCD,KAAKC,8BAA2Bc,CACjC,CAED,gBAAAF,CAAiBG,GAEf,OADYhB,KAAKiB,YACNC,WAAWlB,KAAKmB,WAAWC,QAAQJ,EAC/C,EA1DMnB,EAAAwB,OAAS,CACdC,MAAOC,OACPP,UAAWQ,QAEN3B,EAAA4B,QAAU,CAAC,eCgBPC,EAMX,WAAAC,EAAYV,YAAEA,EAAWW,OAAEA,UACzB5B,KAAK6B,WAAa,IAAIC,IACtB9B,KAAKiB,YAAcjB,KAAK+B,uBAAuBd,GAC/CjB,KAAKmB,UAAYS,EAAOT,UACxBnB,KAAKgC,eAAiBJ,EAAOK,YAE7BC,EAAAlC,KAAKiB,aAAYC,aAAAgB,EAAAhB,WAAe,CAAA,GAChClB,KAAKiB,YAAYC,WAAWlB,KAAKmB,WAAanB,KAE1CA,KAAKgC,gBACPhC,KAAKiB,YAAYkB,SACf,eAAenC,KAAKmB,YACpBnB,KAAKgC,eAGV,CAEO,sBAAAD,CAAuBK,GAC7B,IAAInB,EAAcmB,GAAeC,OAAOC,SAMxC,OAJKrB,IACHA,EAAcsB,EAAYC,QAC1BH,OAAOC,SAAWrB,GAEbA,CACR,CAED,QAAAkB,CAASM,EAAczB,EAAciB,GAEnC,GADAA,IAAAA,EAAejC,KAAKgC,gBAChBhC,KAAK6B,WAAWa,IAAID,GACtB,MAAM,IAAIE,MAAM,cAAcF,6BAIhC,GAFAzC,KAAK6B,WAAWe,IAAIH,EAAMzB,GAEtBiB,EAAY,CACd,MAAMY,EAAiB,eAAe7C,KAAKmB,aCjEhB2B,EDiE8CL,EChEtEK,EAAIC,QAAQ,kBAAmB,SAASC,gBDiE3ChD,KAAKiB,YAAYkB,SAASU,EAAgBZ,EAC3C,CCnE2B,IAACa,CDoE9B,CAED,OAAA1B,CAAQqB,GACN,MAAMzB,EAAYhB,KAAK6B,WAAWoB,IAAIR,GACtC,IAAKzB,EACH,MAAM,IAAI2B,MAAM,sBAAsBF,KAExC,OAAOzB,CACR"}
|
data/lib/turbo/mount/helpers.rb
CHANGED
@@ -3,27 +3,30 @@
|
|
3
3
|
module Turbo
|
4
4
|
module Mount
|
5
5
|
module Helpers
|
6
|
-
def turbo_mount_component(component_name, framework:, props: {}, tag: "div", **attrs)
|
6
|
+
def turbo_mount_component(component_name, framework:, props: {}, tag: "div", **attrs, &block)
|
7
7
|
raise TypeError, "Component name expected" unless component_name.is_a? String
|
8
8
|
|
9
|
-
|
10
|
-
|
9
|
+
controller_name = "turbo-mount-#{framework}-#{component_name.underscore.dasherize}"
|
10
|
+
attrs["data-controller"] = controller_name
|
11
|
+
prefix = "data-#{controller_name}"
|
11
12
|
attrs["#{prefix}-component-value"] = component_name
|
12
13
|
attrs["#{prefix}-props-value"] = json_escape(props.to_json) if props.present?
|
13
14
|
|
14
|
-
content_tag(tag, nil, attrs)
|
15
|
+
return content_tag(tag, nil, attrs) unless block
|
16
|
+
|
17
|
+
content_tag(tag, nil, attrs) { capture(controller_name, &block) }
|
15
18
|
end
|
16
19
|
|
17
|
-
def turbo_mount_react_component(component_name, **attrs)
|
18
|
-
turbo_mount_component(component_name, framework: "react", **attrs)
|
20
|
+
def turbo_mount_react_component(component_name, **attrs, &block)
|
21
|
+
turbo_mount_component(component_name, framework: "react", **attrs, &block)
|
19
22
|
end
|
20
23
|
|
21
|
-
def turbo_mount_svelte_component(component_name, **attrs)
|
22
|
-
turbo_mount_component(component_name, framework: "svelte", **attrs)
|
24
|
+
def turbo_mount_svelte_component(component_name, **attrs, &block)
|
25
|
+
turbo_mount_component(component_name, framework: "svelte", **attrs, &block)
|
23
26
|
end
|
24
27
|
|
25
|
-
def turbo_mount_vue_component(component_name, **attrs)
|
26
|
-
turbo_mount_component(component_name, framework: "vue", **attrs)
|
28
|
+
def turbo_mount_vue_component(component_name, **attrs, &block)
|
29
|
+
turbo_mount_component(component_name, framework: "vue", **attrs, &block)
|
27
30
|
end
|
28
31
|
end
|
29
32
|
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.2.
|
4
|
+
version: 0.2.3
|
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-12 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: railties
|