turbo-mount 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/CHANGELOG.md +22 -0
- data/LICENSE.txt +21 -0
- data/README.md +78 -0
- data/app/assets/javascripts/turbo-mount.js +119 -0
- data/app/assets/javascripts/turbo-mount.min.js +2 -0
- data/app/assets/javascripts/turbo-mount.min.js.map +1 -0
- data/lib/turbo/mount/engine.rb +30 -0
- data/lib/turbo/mount/helpers.rb +30 -0
- data/lib/turbo/mount/version.rb +7 -0
- data/lib/turbo/mount.rb +9 -0
- metadata +74 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 3f99f1305fc0312f04a390c3d7992e5dba4d8aba4bf14349a022cd2af528b5ff
|
4
|
+
data.tar.gz: b29a4f83ee2f6a3ef7b069908644273df3d07d656dee5b963cdc983c6aeebc39
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: ef8a6e260eadec1dad5aa2aff35770d5713c80d31a6a84d0956b7af835cfa5eb994506173cc215dd04cde9da9f3a1a8db15320c95842d21f759eaf6e5453c2fc
|
7
|
+
data.tar.gz: 2d6975c85965b3772089a43e8a6a998537f2c2e15c3dcb41e69e00851fc069eadbac021b44eed119bc11644ffb290b0f26036f11658bb79473c10eedce058179
|
data/CHANGELOG.md
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
# Changelog
|
2
|
+
|
3
|
+
All notable changes to this project will be documented in this file.
|
4
|
+
|
5
|
+
The format is based on [Keep a Changelog],
|
6
|
+
and this project adheres to [Semantic Versioning].
|
7
|
+
|
8
|
+
## [Unreleased]
|
9
|
+
|
10
|
+
## [0.1.0] - 2024-05-07
|
11
|
+
|
12
|
+
### Added
|
13
|
+
|
14
|
+
- Initial implementation. ([@skryukov])
|
15
|
+
|
16
|
+
[@skryukov]: https://github.com/skryukov
|
17
|
+
|
18
|
+
[Unreleased]: https://github.com/skryukov/turbo-mount/compare/v0.1.0...HEAD
|
19
|
+
[0.1.0]: https://github.com/skryukov/turbo-mount/commits/v0.1.0
|
20
|
+
|
21
|
+
[Keep a Changelog]: https://keepachangelog.com/en/1.0.0/
|
22
|
+
[Semantic Versioning]: https://semver.org/spec/v2.0.0.html
|
data/LICENSE.txt
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
The MIT License (MIT)
|
2
|
+
|
3
|
+
Copyright (c) 2024 Svyatoslav Kryukov
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
7
|
+
in the Software without restriction, including without limitation the rights
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
10
|
+
furnished to do so, subject to the following conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be included in
|
13
|
+
all copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
21
|
+
THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,78 @@
|
|
1
|
+
# Turbo::Mount
|
2
|
+
|
3
|
+
[![Gem Version](https://badge.fury.io/rb/turbo-mount.svg)](https://rubygems.org/gems/turbo-mount)
|
4
|
+
|
5
|
+
`Turbo::Mount` is a simple gem that allows you to add highly interactive components from React, Vue, Svelte, and other frameworks to your Hotwire application.
|
6
|
+
|
7
|
+
## Installation
|
8
|
+
|
9
|
+
Install the gem and add to the application's Gemfile by executing:
|
10
|
+
|
11
|
+
$ bundle add turbo-mount
|
12
|
+
|
13
|
+
If bundler is not being used to manage dependencies, install the gem by executing:
|
14
|
+
|
15
|
+
$ gem install turbo-mount
|
16
|
+
|
17
|
+
## Usage
|
18
|
+
|
19
|
+
First, you need to initialize `TurboMount` and register the components you want to use:
|
20
|
+
|
21
|
+
```js
|
22
|
+
import { Application } from "@hotwired/stimulus"
|
23
|
+
import { TurboMount } from "turbo-mount"
|
24
|
+
|
25
|
+
const application = Application.start()
|
26
|
+
|
27
|
+
// Initialize TurboMount and register the react stimulus controller
|
28
|
+
const turboMount = new TurboMount({application, framework: "react"});
|
29
|
+
|
30
|
+
// Register the components you want to use
|
31
|
+
import { SketchPicker } from 'react-color'
|
32
|
+
turboMount.register('SketchPicker', SketchPicker);
|
33
|
+
```
|
34
|
+
|
35
|
+
Now you can use view helpers to mount the components:
|
36
|
+
|
37
|
+
```erb
|
38
|
+
<%= turbo_mount_component("SketchPicker", framework: "react", props: {color: "#034"}) %>
|
39
|
+
|
40
|
+
<%# or using alias %>
|
41
|
+
|
42
|
+
<%= turbo_mount_react_component("SketchPicker", props: {color: "#430"}) %>
|
43
|
+
```
|
44
|
+
|
45
|
+
In case you need to customize the component's behavior, or pass functions as props, you can create a custom controller:
|
46
|
+
|
47
|
+
```js
|
48
|
+
// javascript/controllers/turbo_mount_react_sketch_picker_controller.js
|
49
|
+
|
50
|
+
import { TurboMountReactController } from "turbo-mount"
|
51
|
+
|
52
|
+
export default class extends TurboMountReactController {
|
53
|
+
get componentProps() {
|
54
|
+
return {
|
55
|
+
...this.propsValue,
|
56
|
+
onChange: this.onChange,
|
57
|
+
};
|
58
|
+
}
|
59
|
+
|
60
|
+
onChange = (color) => {
|
61
|
+
this.propsValue = { ...this.propsValue, color: color.hex };
|
62
|
+
};
|
63
|
+
}
|
64
|
+
```
|
65
|
+
|
66
|
+
## Development
|
67
|
+
|
68
|
+
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.
|
69
|
+
|
70
|
+
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).
|
71
|
+
|
72
|
+
## Contributing
|
73
|
+
|
74
|
+
Bug reports and pull requests are welcome on GitHub at https://github.com/skryukov/turbo-mount.
|
75
|
+
|
76
|
+
## License
|
77
|
+
|
78
|
+
The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
|
@@ -0,0 +1,119 @@
|
|
1
|
+
import { Controller } from '@hotwired/stimulus';
|
2
|
+
import { createElement } from 'react';
|
3
|
+
import { createRoot } from 'react-dom/client';
|
4
|
+
import { createApp } from 'vue';
|
5
|
+
|
6
|
+
class TurboMountController extends Controller {
|
7
|
+
connect() {
|
8
|
+
this._umountComponentCallback || (this._umountComponentCallback = this.mountComponent(this.mountElement, this.resolvedComponent, this.componentProps));
|
9
|
+
}
|
10
|
+
disconnect() {
|
11
|
+
this.umountComponent();
|
12
|
+
}
|
13
|
+
propsValueChanged() {
|
14
|
+
this.umountComponent();
|
15
|
+
this._umountComponentCallback = this.mountComponent(this.mountElement, this.resolvedComponent, this.componentProps);
|
16
|
+
}
|
17
|
+
get componentProps() {
|
18
|
+
return this.propsValue;
|
19
|
+
}
|
20
|
+
get mountElement() {
|
21
|
+
return this.element;
|
22
|
+
}
|
23
|
+
get resolvedComponent() {
|
24
|
+
return this.resolveComponent(this.componentValue);
|
25
|
+
}
|
26
|
+
umountComponent() {
|
27
|
+
this._umountComponentCallback && this._umountComponentCallback();
|
28
|
+
this._umountComponentCallback = undefined;
|
29
|
+
}
|
30
|
+
resolveComponent(component) {
|
31
|
+
const app = this.application;
|
32
|
+
return app.turboMount[this.framework].resolve(component);
|
33
|
+
}
|
34
|
+
}
|
35
|
+
TurboMountController.values = {
|
36
|
+
props: Object,
|
37
|
+
component: String
|
38
|
+
};
|
39
|
+
|
40
|
+
class TurboMountReactController extends TurboMountController {
|
41
|
+
constructor() {
|
42
|
+
super(...arguments);
|
43
|
+
this.framework = "react";
|
44
|
+
}
|
45
|
+
mountComponent(el, Component, props) {
|
46
|
+
const root = createRoot(el);
|
47
|
+
root.render(createElement(Component, props));
|
48
|
+
return root.unmount;
|
49
|
+
}
|
50
|
+
}
|
51
|
+
|
52
|
+
class TurboMountSvelteController extends TurboMountController {
|
53
|
+
constructor() {
|
54
|
+
super(...arguments);
|
55
|
+
this.framework = "svelte";
|
56
|
+
}
|
57
|
+
mountComponent(el, Component, props) {
|
58
|
+
const component = new Component({ target: el, props });
|
59
|
+
return component.$destroy;
|
60
|
+
}
|
61
|
+
}
|
62
|
+
|
63
|
+
class TurboMountVueController extends TurboMountController {
|
64
|
+
constructor() {
|
65
|
+
super(...arguments);
|
66
|
+
this.framework = "vue";
|
67
|
+
}
|
68
|
+
mountComponent(el, Component, props) {
|
69
|
+
const app = createApp(Component, props);
|
70
|
+
app.mount(el);
|
71
|
+
return app.unmount;
|
72
|
+
}
|
73
|
+
}
|
74
|
+
|
75
|
+
class TurboMount {
|
76
|
+
constructor(props) {
|
77
|
+
var _a;
|
78
|
+
this.components = new Map();
|
79
|
+
this.application = props.application;
|
80
|
+
this.framework = props.framework;
|
81
|
+
this.baseController = undefined;
|
82
|
+
if (!this.framework) {
|
83
|
+
throw new Error('framework is required');
|
84
|
+
}
|
85
|
+
(_a = this.application).turboMount || (_a.turboMount = {});
|
86
|
+
this.application.turboMount[this.framework] = this;
|
87
|
+
this.baseController = TurboMount.frameworkControllers.get(this.framework);
|
88
|
+
if (this.baseController) {
|
89
|
+
this.application.register(`turbo-mount-${this.framework}`, this.baseController);
|
90
|
+
}
|
91
|
+
}
|
92
|
+
register(name, component, controller) {
|
93
|
+
controller || (controller = this.baseController);
|
94
|
+
if (this.components.has(name)) {
|
95
|
+
throw new Error(`Component '${name}' is already registered.`);
|
96
|
+
}
|
97
|
+
this.components.set(name, component);
|
98
|
+
if (controller) {
|
99
|
+
const controllerName = `turbo-mount-${this.framework}-${this.camelToKebabCase(name)}`;
|
100
|
+
this.application.register(controllerName, controller);
|
101
|
+
}
|
102
|
+
}
|
103
|
+
resolve(name) {
|
104
|
+
const component = this.components.get(name);
|
105
|
+
if (!component) {
|
106
|
+
throw new Error(`Unknown component: ${name}`);
|
107
|
+
}
|
108
|
+
return component;
|
109
|
+
}
|
110
|
+
camelToKebabCase(str) {
|
111
|
+
return str.replace(/([a-z])([A-Z])/g, '$1-$2').toLowerCase();
|
112
|
+
}
|
113
|
+
}
|
114
|
+
TurboMount.frameworkControllers = new Map();
|
115
|
+
TurboMount.frameworkControllers.set("react", TurboMountReactController);
|
116
|
+
TurboMount.frameworkControllers.set("svelte", TurboMountSvelteController);
|
117
|
+
TurboMount.frameworkControllers.set("vue", TurboMountVueController);
|
118
|
+
|
119
|
+
export { TurboMount, TurboMountController, TurboMountReactController, TurboMountSvelteController, TurboMountVueController };
|
@@ -0,0 +1,2 @@
|
|
1
|
+
import{Controller as t}from"@hotwired/stimulus";import{createElement as o}from"react";import{createRoot as e}from"react-dom/client";import{createApp as r}from"vue";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.mountComponent(this.mountElement,this.resolvedComponent,this.componentProps)}get componentProps(){return this.propsValue}get mountElement(){return 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};class s extends n{constructor(){super(...arguments),this.framework="react"}mountComponent(t,r,n){const s=e(t);return s.render(o(r,n)),s.unmount}}class m extends n{constructor(){super(...arguments),this.framework="svelte"}mountComponent(t,o,e){return new o({target:t,props:e}).$destroy}}class i extends n{constructor(){super(...arguments),this.framework="vue"}mountComponent(t,o,e){const n=r(o,e);return n.mount(t),n.unmount}}class a{constructor(t){var o;if(this.components=new Map,this.application=t.application,this.framework=t.framework,this.baseController=void 0,!this.framework)throw new Error("framework is required");(o=this.application).turboMount||(o.turboMount={}),this.application.turboMount[this.framework]=this,this.baseController=a.frameworkControllers.get(this.framework),this.baseController&&this.application.register(`turbo-mount-${this.framework}`,this.baseController)}register(t,o,e){if(e||(e=this.baseController),this.components.has(t))throw new Error(`Component '${t}' is already registered.`);if(this.components.set(t,o),e){const o=`turbo-mount-${this.framework}-${this.camelToKebabCase(t)}`;this.application.register(o,e)}}resolve(t){const o=this.components.get(t);if(!o)throw new Error(`Unknown component: ${t}`);return o}camelToKebabCase(t){return t.replace(/([a-z])([A-Z])/g,"$1-$2").toLowerCase()}}a.frameworkControllers=new Map,a.frameworkControllers.set("react",s),a.frameworkControllers.set("svelte",m),a.frameworkControllers.set("vue",i);export{a as TurboMount,n as TurboMountController,s as TurboMountReactController,m as TurboMountSvelteController,i as TurboMountVueController};
|
2
|
+
//# sourceMappingURL=turbo-mount.min.js.map
|
@@ -0,0 +1 @@
|
|
1
|
+
{"version":3,"file":"turbo-mount.min.js","sources":["../src/controllers/turbo-mount-controller.ts","../src/controllers/turbo-mount-react-controller.ts","../src/turbo-mount.ts"],"sourcesContent":["import {Controller, ControllerConstructor} 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 declare readonly propsValue: object;\n declare readonly componentValue: string;\n\n abstract framework: string;\n\n abstract mountComponent(el: Element, component: string, props: object): () => void;\n\n umountComponentCallback?: () => void;\n\n connect() {\n this.umountComponentCallback ||= this.mountComponent(this.element, this.componentValue, this.propsValue);\n }\n\n disconnect() {\n this.umountComponent();\n }\n\n propsValueChanged() {\n this.umountComponent();\n this.umountComponentCallback = this.mountComponent(this.element, this.componentValue, this.componentProps);\n }\n\n get componentProps() {\n return this.propsValue;\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 static shouldRegister(controllerConstructor: ControllerConstructor, identifier: string, application: ApplicationWithTurboMount<any>) {\n const framework = identifier.split('-')[2];\n console.log({\n framework,\n identifier,\n modules: application.router.modules.map(m => m.identifier)\n })\n if (framework && identifier.startsWith(`turbo-mount-${framework}-`)\n && application.router.modules.find(m => m.identifier === identifier)) {\n console.log(controllerConstructor, application.turboMount[framework].baseController)\n return controllerConstructor !== application.turboMount[framework].baseController;\n }\n\n return true;\n }\n}\n\n\n","import {createElement, ComponentType} from \"react\";\nimport {createRoot} from \"react-dom/client\";\n\nimport {TurboMountController} from \"./turbo-mount-controller\";\n\nexport class TurboMountReactController extends TurboMountController<ComponentType> {\n framework = \"react\"\n\n mountComponent(el: Element, component: string, props: object) {\n const Component = this.resolveComponent(component);\n const root = createRoot(el);\n\n root.render(createElement(Component, props))\n\n return () => {\n root.unmount()\n }\n }\n}\n","import {Application, ControllerConstructor} from '@hotwired/stimulus';\nimport {TurboMountReactController} from \"./controllers\";\n\nexport interface ApplicationWithTurboMount<T> extends Application {\n turboMount: { [framework: string]: TurboMount<T> };\n}\n\nexport class TurboMount<T> {\n static frameworkControllers: Map<string, ControllerConstructor> = new Map();\n\n components: Map<string, T>;\n application: ApplicationWithTurboMount<T>;\n framework: string;\n baseController?: ControllerConstructor;\n\n constructor(props: { application: Application, framework: string }) {\n this.components = new Map();\n this.application = props.application as ApplicationWithTurboMount<T>;\n this.framework = props.framework;\n this.baseController = undefined;\n\n if (!this.framework) {\n throw new Error('framework is required');\n }\n\n this.application.turboMount ||= {};\n this.application.turboMount[this.framework] = this;\n\n this.baseController = TurboMount.frameworkControllers.get(this.framework);\n\n if (this.baseController) {\n this.application.register(`turbo-mount-${this.framework}`, this.baseController);\n }\n }\n\n camelToKebabCase(str: string) {\n return str.replace(/([a-z])([A-Z])/g, '$1-$2').toLowerCase();\n }\n\n register(name: string, component: T) {\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 (this.baseController) {\n const controllerName = `turbo-mount-${this.framework}-${this.camelToKebabCase(name)}`;\n if (!this.application.router.modules.find(m => m.identifier === controllerName)) {\n this.application.register(controllerName, this.baseController);\n }\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\nTurboMount.frameworkControllers.set(\"react\", TurboMountReactController)\n"],"names":["TurboMountController","Controller","connect","this","umountComponentCallback","mountComponent","element","componentValue","propsValue","disconnect","umountComponent","propsValueChanged","componentProps","undefined","resolveComponent","component","application","turboMount","framework","resolve","shouldRegister","controllerConstructor","identifier","split","console","log","modules","router","map","m","startsWith","find","baseController","values","props","Object","String","TurboMountReactController","constructor","el","Component","root","createRoot","render","createElement","unmount","TurboMount","components","Map","Error","_a","frameworkControllers","get","register","camelToKebabCase","str","replace","toLowerCase","name","has","set","controllerName"],"mappings":"oIAGM,MAAgBA,UAAgCC,EAclD,OAAAC,GACIC,KAAKC,0BAALD,KAAKC,wBAA4BD,KAAKE,eAAeF,KAAKG,QAASH,KAAKI,eAAgBJ,KAAKK,YAChG,CAED,UAAAC,GACIN,KAAKO,iBACR,CAED,iBAAAC,GACIR,KAAKO,kBACLP,KAAKC,wBAA0BD,KAAKE,eAAeF,KAAKG,QAASH,KAAKI,eAAgBJ,KAAKS,eAC9F,CAED,kBAAIA,GACA,OAAOT,KAAKK,UACf,CAED,eAAAE,GACIP,KAAKC,yBAA2BD,KAAKC,0BACrCD,KAAKC,6BAA0BS,CAClC,CAED,gBAAAC,CAAiBC,GAEb,OADYZ,KAAKa,YACNC,WAAWd,KAAKe,WAAWC,QAAQJ,EACjD,CAED,qBAAOK,CAAeC,EAA8CC,EAAoBN,GACpF,MAAME,EAAYI,EAAWC,MAAM,KAAK,GAMxC,OALAC,QAAQC,IAAI,CACRP,YACAI,aACAI,QAASV,EAAYW,OAAOD,QAAQE,KAAIC,GAAKA,EAAEP,iBAE/CJ,GAAaI,EAAWQ,WAAW,eAAeZ,OAC/CF,EAAYW,OAAOD,QAAQK,MAAKF,GAAKA,EAAEP,aAAeA,OACzDE,QAAQC,IAAIJ,EAAuBL,EAAYC,WAAWC,GAAWc,gBAC9DX,IAA0BL,EAAYC,WAAWC,GAAWc,eAI1E,EAtDMhC,EAAAiC,OAAS,CACZC,MAAOC,OACPpB,UAAWqB,QCDb,MAAOC,UAAkCrC,EAA/C,WAAAsC,uBACInC,KAASe,UAAG,OAYf,CAVG,cAAAb,CAAekC,EAAaxB,EAAmBmB,GAC3C,MAAMM,EAAYrC,KAAKW,iBAAiBC,GAClC0B,EAAOC,EAAWH,GAIxB,OAFAE,EAAKE,OAAOC,EAAcJ,EAAWN,IAE9B,KACHO,EAAKI,SAAS,CAErB,QCVQC,EAQT,WAAAR,CAAYJ,SAMR,GALA/B,KAAK4C,WAAa,IAAIC,IACtB7C,KAAKa,YAAckB,EAAMlB,YACzBb,KAAKe,UAAYgB,EAAMhB,UACvBf,KAAK6B,oBAAiBnB,GAEjBV,KAAKe,UACN,MAAM,IAAI+B,MAAM,0BAGpBC,EAAA/C,KAAKa,aAAYC,aAAAiC,EAAAjC,WAAe,CAAA,GAChCd,KAAKa,YAAYC,WAAWd,KAAKe,WAAaf,KAE9CA,KAAK6B,eAAiBc,EAAWK,qBAAqBC,IAAIjD,KAAKe,WAE3Df,KAAK6B,gBACL7B,KAAKa,YAAYqC,SAAS,eAAelD,KAAKe,YAAaf,KAAK6B,eAEvE,CAED,gBAAAsB,CAAiBC,GACb,OAAOA,EAAIC,QAAQ,kBAAmB,SAASC,aAClD,CAED,QAAAJ,CAASK,EAAc3C,GACnB,GAAIZ,KAAK4C,WAAWY,IAAID,GACpB,MAAM,IAAIT,MAAM,cAAcS,6BAIlC,GAFAvD,KAAK4C,WAAWa,IAAIF,EAAM3C,GAEtBZ,KAAK6B,eAAgB,CACrB,MAAM6B,EAAiB,eAAe1D,KAAKe,aAAaf,KAAKmD,iBAAiBI,KACzEvD,KAAKa,YAAYW,OAAOD,QAAQK,MAAKF,GAAKA,EAAEP,aAAeuC,KAC5D1D,KAAKa,YAAYqC,SAASQ,EAAgB1D,KAAK6B,eAEtD,CACJ,CAED,OAAAb,CAAQuC,GACJ,MAAM3C,EAAYZ,KAAK4C,WAAWK,IAAIM,GACtC,IAAK3C,EACD,MAAM,IAAIkC,MAAM,sBAAsBS,KAE1C,OAAO3C,CACV,EAnDM+B,EAAAK,qBAA2D,IAAIH,IAsD1EF,EAAWK,qBAAqBS,IAAI,QAASvB"}
|
@@ -0,0 +1,30 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "rails/engine"
|
4
|
+
require "turbo/mount/helpers"
|
5
|
+
|
6
|
+
module Turbo
|
7
|
+
module Mount
|
8
|
+
class Engine < Rails::Engine
|
9
|
+
# If you don't want to precompile assets (e.g., you're using jsbundling),
|
10
|
+
# you can do this in an initializer:
|
11
|
+
#
|
12
|
+
# config.after_initialize do
|
13
|
+
# config.assets.precompile -= Turbo::Mount::Engine::PRECOMPILE_ASSETS
|
14
|
+
# end
|
15
|
+
PRECOMPILE_ASSETS = %w[turbo-mount.js turbo-mount.min.js turbo-mount.min.js.map].freeze
|
16
|
+
|
17
|
+
initializer "turbo-mount.assets" do
|
18
|
+
if Rails.application.config.respond_to?(:assets)
|
19
|
+
Rails.application.config.assets.precompile += PRECOMPILE_ASSETS
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
initializer "turbo-mount.helpers" do
|
24
|
+
ActiveSupport.on_load(:action_controller_base) do
|
25
|
+
helper Turbo::Mount::Helpers
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Turbo
|
4
|
+
module Mount
|
5
|
+
module Helpers
|
6
|
+
def turbo_mount_component(component_name, framework:, props: {}, tag: "div", **attrs)
|
7
|
+
raise TypeError, "Component name expected" unless component_name.is_a? String
|
8
|
+
|
9
|
+
attrs["data-controller"] = "turbo-mount-#{framework}-#{component_name.underscore.dasherize}"
|
10
|
+
prefix = "data-#{attrs["data-controller"]}"
|
11
|
+
attrs["#{prefix}-component-value"] = component_name
|
12
|
+
attrs["#{prefix}-props-value"] = json_escape(props.to_json) if props.present?
|
13
|
+
|
14
|
+
content_tag(tag, nil, attrs)
|
15
|
+
end
|
16
|
+
|
17
|
+
def turbo_mount_react_component(component_name, **attrs)
|
18
|
+
turbo_mount_component(component_name, framework: "react", **attrs)
|
19
|
+
end
|
20
|
+
|
21
|
+
def turbo_mount_svelte_component(component_name, **attrs)
|
22
|
+
turbo_mount_component(component_name, framework: "svelte", **attrs)
|
23
|
+
end
|
24
|
+
|
25
|
+
def turbo_mount_vue_component(component_name, **attrs)
|
26
|
+
turbo_mount_component(component_name, framework: "vue", **attrs)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
data/lib/turbo/mount.rb
ADDED
metadata
ADDED
@@ -0,0 +1,74 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: turbo-mount
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Svyatoslav Kryukov
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2024-05-07 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: railties
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ">="
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: 6.0.0
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ">="
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: 6.0.0
|
27
|
+
description: Add highly interactive components to your Hotwire application with Turbo
|
28
|
+
Mount.
|
29
|
+
email:
|
30
|
+
- me@skryukov.dev
|
31
|
+
executables: []
|
32
|
+
extensions: []
|
33
|
+
extra_rdoc_files: []
|
34
|
+
files:
|
35
|
+
- CHANGELOG.md
|
36
|
+
- LICENSE.txt
|
37
|
+
- README.md
|
38
|
+
- app/assets/javascripts/turbo-mount.js
|
39
|
+
- app/assets/javascripts/turbo-mount.min.js
|
40
|
+
- app/assets/javascripts/turbo-mount.min.js.map
|
41
|
+
- lib/turbo/mount.rb
|
42
|
+
- lib/turbo/mount/engine.rb
|
43
|
+
- lib/turbo/mount/helpers.rb
|
44
|
+
- lib/turbo/mount/version.rb
|
45
|
+
homepage: https://github.com/skryukov/turbo-mount
|
46
|
+
licenses:
|
47
|
+
- MIT
|
48
|
+
metadata:
|
49
|
+
bug_tracker_uri: https://github.com/skryukov/turbo-mount/issues
|
50
|
+
changelog_uri: https://github.com/skryukov/turbo-mount/blob/main/CHANGELOG.md
|
51
|
+
documentation_uri: https://github.com/skryukov/turbo-mount/blob/main/README.md
|
52
|
+
homepage_uri: https://github.com/skryukov/turbo-mount
|
53
|
+
source_code_uri: https://github.com/skryukov/turbo-mount
|
54
|
+
rubygems_mfa_required: 'true'
|
55
|
+
post_install_message:
|
56
|
+
rdoc_options: []
|
57
|
+
require_paths:
|
58
|
+
- lib
|
59
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
60
|
+
requirements:
|
61
|
+
- - ">="
|
62
|
+
- !ruby/object:Gem::Version
|
63
|
+
version: 3.0.0
|
64
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - ">="
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '0'
|
69
|
+
requirements: []
|
70
|
+
rubygems_version: 3.5.7
|
71
|
+
signing_key:
|
72
|
+
specification_version: 4
|
73
|
+
summary: Use React, Vue, Svelte, and other components with Hotwire.
|
74
|
+
test_files: []
|