Skip to content

Commit f2e8d2e

Browse files
authored
Merge pull request #37 from jaredmcateer/support-global-components
2 parents eea62c7 + 0a5f468 commit f2e8d2e

File tree

9 files changed

+119
-15
lines changed

9 files changed

+119
-15
lines changed

.changeset/famous-kids-mate.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"@jaredmcateer/ngvue3": minor
3+
---
4+
5+
Adds support for global components

.github/workflows/test.yml

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
name: Tests
2+
on:
3+
push:
4+
branches:
5+
- "*"
6+
- "*/*"
7+
- "**"
8+
- "!main"
9+
jobs:
10+
test:
11+
runs-on: ubuntu-latest
12+
steps:
13+
- name: Checkout 🛎️
14+
uses: actions/checkout@v3
15+
16+
- name: Setup pnpm 💫
17+
uses: pnpm/action-setup@v2
18+
with:
19+
version: 7.0.0
20+
21+
- name: Use Node.js 16.xa 💻
22+
uses: actions/setup-node@v3
23+
with:
24+
version: 16
25+
cache: pnpm
26+
27+
- name: Install Dependencies 🗂️
28+
run: pnpm install --frozen-lockfile
29+
30+
- name: Test 🔬️
31+
run: pnpm test

packages/ngVue3/README.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ ngVue 3 is a fork of the [ngVue](https://github.com/ngVue/ngVue) project which i
1818
- [Notes](#notes)
1919
- [`v-on-*`](#v-on-)
2020
- [Handling HTML Attributes](#handling-html-attributes)
21-
- [Plugins, Injectables and Directives](#plugins-injectables-and-directives)
21+
- [Plugins, Injectables, Directives and Global Components](#plugins-injectables-directives-and-global-components)
2222
- [Directives usage](#directives-usage)
2323
- [TODO](#todo)
2424

@@ -254,11 +254,11 @@ Keep in mind that hwne you pass down literal strings for anything other than `cl
254254
</template>
255255
```
256256

257-
## Plugins, Injectables and Directives
257+
## Plugins, Injectables, Directives and Global Components
258258

259259
Due to the architectural changes introduced by Vue 3 in most cases if you need access to lifecycle hooks you can simply create a composable and use it directly in your vue components. However, there are instances you need to install plugins (e.g., Pinia/Vuex, VueRouter, etc), directives or you want access to shared logic in your angular app. Plugins in ngVue 3 have been revamped to be simpler, access to "root" props is no longer possible, however you can now pass through Plugins, Injectables and Directive easily as well as still create your own custom ngVue Plugin.
260260

261-
[Plugin, Injectables and Directives Documentation](./docs/plugins.md)
261+
[Plugin, Injectables, Directives and Global Components Documentation](./docs/plugins.md)
262262

263263
### Directives usage
264264

packages/ngVue3/docs/plugins.md

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,14 +17,15 @@ angular.module("mainApp", [useNgVue(), useNgVuePlugins()]);
1717

1818
`useNgVuePlugins` creates an Angular service `$ngVue`. This service implements a custom plugins system and a means to pass through Injectables and Plugins to the Vue app instance.
1919

20-
### Provide/Use/Directives
20+
### Provide/Use/Directives/Global Components
2121

2222
Sometimes you simply need to add a plugin, injectable or directive to the app instance, you don't have any specific need for angular but due to ngVue's architecture the app instance isn't readily available, `$ngVueProvider` has pass through function to help you with that.
2323

2424
_Example using TypeScript_
2525

2626
```ts
2727
import { type NgVueProvider } from "@jaredmcateer/ngvue3";
28+
import MyGlobalComponent from "./components/MyGlobalComponent.vue";
2829
const fooKey: InjectionKey<"bar"> = new Symbol();
2930

3031
angular
@@ -41,12 +42,16 @@ angular
4142
el.focus();
4243
},
4344
});
45+
46+
// Register global component
47+
$ngVueProvider.component("myGlobalComponent", MyGlobalComponent);
4448
});
4549
```
4650

4751
<details><summary><strong>Equivalent using JavaScript</strong></summary>
4852

4953
```javascript
54+
import MyGlobalComponent from "./components/MyGlobalComponent.vue";
5055
export const fooKey = Symbol();
5156

5257
angular.module("mainApp", [useNgVue(), useNgVuePlugins()]).config(($ngVueProvider) => {
@@ -60,6 +65,9 @@ angular.module("mainApp", [useNgVue(), useNgVuePlugins()]).config(($ngVueProvide
6065
el.focus();
6166
},
6267
});
68+
69+
// Register global component
70+
$ngVueProvider.component("myGlobalComponent", MyGlobalComponent);
6371
});
6472
```
6573

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
<script setup lang="ts">
2+
import { ref } from "vue";
3+
const name = ref("Jane");
4+
</script>
5+
6+
<template>
7+
<my-global-component :name="name"></my-global-component>
8+
</template>
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
<script setup lang="ts">
2+
defineProps<{ name: string }>();
3+
</script>
4+
5+
<template>
6+
<div class="my-global-component">Hello {{ name }}!</div>
7+
</template>

packages/ngVue3/lib/angular/__tests__/ngVueProvider.test.ts

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@ import { NgVueProvider, useNgVuePlugins } from "../ngVueProvider";
55
import { CustomNgVuePluginConfig, useCustomNgVuePlugin } from "./__fixtures__/NgVuePlugin";
66
import Button from "./__fixtures__/Button.vue";
77
import { MyService, MyServiceKey } from "./__fixtures__/MyService";
8+
import GlobalComponentConsumer from "./__fixtures__/GlobalComponentConsumer.vue";
9+
import MyGlobalComponent from "./__fixtures__/MyGlobalComponent.vue";
810

911
interface TestScope extends angular.IScope {
1012
handleButtonClick: (val: number) => number;
@@ -67,13 +69,18 @@ describe("NgVueProvider", () => {
6769
},
6870
});
6971

72+
ngVueProvider.component("myGlobalComponent", MyGlobalComponent);
73+
7074
(ngVueProvider.plugins.customNgVuePlugin as CustomNgVuePluginConfig).register([
7175
"make",
7276
"colour",
7377
"quantity",
7478
]);
7579

7680
$compileProvider.directive(...ngVueComponent("myButton", Button));
81+
$compileProvider.directive(
82+
...ngVueComponent("globalComponentConsumer", GlobalComponentConsumer)
83+
);
7784
}
7885
)
7986
);
@@ -173,5 +180,28 @@ describe("NgVueProvider", () => {
173180
expect(element.find("span")[2].textContent).toEqual("HELLO!?");
174181
});
175182
});
183+
184+
describe("global components", () => {
185+
beforeEach(
186+
angular.mock.inject(
187+
(_$rootScope_: angular.IRootScopeService, _$compile_: angular.ICompileService) => {
188+
compile = ngHtmlCompiler(_$compile_);
189+
scope = (function (): TestScope {
190+
const tmpScope: any = _$rootScope_.$new();
191+
tmpScope.handleButtonClick = jest.fn();
192+
return tmpScope;
193+
})();
194+
195+
element = compile(`<global-component-consumer></global-component-consumer>`, scope);
196+
}
197+
)
198+
);
199+
200+
it("should render a global component", () => {
201+
expect(element.find("div")[0]).toBeDefined();
202+
expect(element.find("div")[0].classList.contains("my-global-component")).toBeTruthy();
203+
expect(element.find("div")[0].textContent).toEqual("Hello Jane!");
204+
});
205+
});
176206
});
177207
});

packages/ngVue3/lib/angular/ngVueLinker.ts

Lines changed: 14 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -125,22 +125,26 @@ function createAppInstance(
125125
}
126126

127127
/**
128-
* Loads the globals such as Injectables, Plugins and Directives that has been
129-
* added via the ngVueProvider
128+
* Loads the globals such as Injectables, Plugins, Directives, and Components
129+
* that has been added via the ngVueProvider
130130
*
131131
* @param vueInstance
132132
* @param $injector
133133
*/
134134
function loadNgVueGlobals(vueInstance: App<Element>, $injector: ng.auto.IInjectorService) {
135135
const $ngVue: NgVueService | null = $injector.has("$ngVue") ? $injector.get("$ngVue") : null;
136-
if ($ngVue) {
137-
$ngVue.initNgVuePlugins(vueInstance);
138-
$ngVue.getVuePlugins().forEach((plugin) => vueInstance.use(plugin));
139-
$ngVue.getInjectables().forEach(([key, value]) => vueInstance.provide(key, value));
140-
Object.entries($ngVue.getVueDirectives()).forEach(([name, directive]) =>
141-
vueInstance.directive(name, directive)
142-
);
143-
}
136+
137+
if (!$ngVue) return;
138+
139+
$ngVue.initNgVuePlugins(vueInstance);
140+
$ngVue.getVuePlugins().forEach((plugin) => vueInstance.use(plugin));
141+
$ngVue.getInjectables().forEach(([key, value]) => vueInstance.provide(key, value));
142+
Object.entries($ngVue.getVueDirectives()).forEach(([name, directive]) =>
143+
vueInstance.directive(name, directive)
144+
);
145+
Object.entries($ngVue.getVueComponents()).forEach(([name, component]) =>
146+
vueInstance.component(name, component)
147+
);
144148
}
145149

146150
function getInnerHtml(element: HTMLElement) {

packages/ngVue3/lib/angular/ngVueProvider.ts

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import angular from "angular";
2-
import { App, Directive, InjectionKey, Plugin } from "vue";
2+
import { App, Directive, InjectionKey, Plugin, Component } from "vue";
33

44
export type PluginHook = ($injector: ng.auto.IInjectorService, app: App<Element>) => void;
55

@@ -20,6 +20,7 @@ export interface NgVueService {
2020
getInjectables(): NgVueInjectable[];
2121
getVuePlugins(): Plugin[];
2222
getVueDirectives(): Record<string, Directive>;
23+
getVueComponents(): Record<string, Component>;
2324
}
2425

2526
export class NgVueProvider {
@@ -31,6 +32,7 @@ export class NgVueProvider {
3132
private injectables: NgVueInjectable[] = [];
3233
private nativeVuePlugins: Plugin[] = [];
3334
private nativeVueDirectives: Record<string, Directive> = {};
35+
private nativeVueComponents: Record<string, Component> = {};
3436

3537
constructor(private $injector: ng.auto.IInjectorService) {
3638
this.$get = [
@@ -49,6 +51,7 @@ export class NgVueProvider {
4951
getInjectables: () => this.injectables,
5052
getVuePlugins: () => this.nativeVuePlugins,
5153
getVueDirectives: () => this.nativeVueDirectives,
54+
getVueComponents: () => this.nativeVueComponents,
5255
};
5356
},
5457
];
@@ -86,6 +89,14 @@ export class NgVueProvider {
8689
this.nativeVueDirectives[name] = vueDirective;
8790
}
8891

92+
/**
93+
* Acts as a pass through for native vue components to the app instance.
94+
* @param vueComponent
95+
*/
96+
component(name: string, vueComponent: Component) {
97+
this.nativeVueComponents[name] = vueComponent;
98+
}
99+
89100
/**
90101
* Installs an ngVue plugin, this gives access to configuration via the
91102
* ngVueProvider and gives the Vue plugin install method access to the angular

0 commit comments

Comments
 (0)