diff --git a/.angular-cli.json b/.angular-cli.json
index 4a640df..7138974 100644
--- a/.angular-cli.json
+++ b/.angular-cli.json
@@ -26,7 +26,8 @@
"environments": {
"dev": "environments/environment.ts",
"prod": "environments/environment.prod.ts"
- }
+ },
+ "showCircularDependencies": false
}
],
"e2e": {
@@ -55,6 +56,9 @@
},
"defaults": {
"styleExt": "css",
- "component": {}
+ "component": {},
+ "build": {
+ "showCircularDependencies": false
+ }
}
}
diff --git a/README.md b/README.md
index 69bbad8..042f0f5 100644
--- a/README.md
+++ b/README.md
@@ -1,185 +1,105 @@
-### WIP !
-
-# ng2-right-click-menu
+## ng2-right-click-menu
_Right click context menu for Angular 2+_
__DEMO__ https://msarsha.github.io/ng2-right-click-menu/
-## How to use
+### Dependencies
-- `npm install --save ng2-right-click-menu`
-- import `ShContextMenuModule` into your app module
+`@angular/cdk`
-Add the `[sh-context]` directive to the desired element and bind an `IShContextMenuItem` array.
+`@angular/cdk/overlay-prebuilt.css"`
-Use the `[sh-data-context]` property to inject a context object of type `any`.
+### Setup
-````html
-
- // content
-
-````
+`npm install --save ng2-right-click-menu @angular/cdk`
-### `[sh-context]` (`IShContextMenuItem[]`)
+import `ShContextMenuModule`
````typescript
- interface IShContextMenuItem {
- label?: ((context: any) => string) | string; // as of version 0.0.11 this property is rendered as HTML
- divider?: boolean;
- onClick?($event: any): void;
- visible?(context: any): boolean;
- disabled?(context: any): boolean;
- subMenu?: boolean;
- subMenuItems?: IShContextMenuItem[];
-}
-````
-
-Example:
+import {ShContextMenuModule} from 'ng2-right-click-menu'
-````typescript
- items: IShContextMenuItem[];
-
- this.items = [
- {
- label: 'Save',
- onClick: this.clickEvent
- },
- {
- label: (context) => `Edit ${context.someVariable}`,
- onClick: this.clickEvent
- },
- {
- label: 'Sub Menu',
- subMenu: true,
- subMenuItems: [
- {
- label: 'Save',
- onClick: this.clickEvent
- },
- {
- label: 'Edit',
- onClick: this.clickEvent
- }]
- }
- {
- divider: true
- },
- {
- label: 'Remove',
- disabled: ctx => {
- return ctx.Two === 'Two';
- },
- onClick: this.clickEvent
- },
- {
- label: (context) => `Hide ${context.name}`,
- onClick: this.clickEvent,
- visible: ctx => {
- return ctx.One === 'One';
- }
- }
- ];
-
- clickEvent($event: any){
- console.log('clicked ', $event);
- };
+@NgModule({
+ //...
+ imports: [ShContextMenuModule]
+ //...
+})
````
-### Passing a function to the label option
+import css file in your `styles.css`:
-You can pass either a string or a function that returns a string (using the data context as a parameter) to the `label` option of menu items. Passing a function allows the label to contain dynamic content.
-
-### onBeforeMenuOpen (v0.0.14)
-
-The `onBeforeMenuOpen` event can be used to cancel the menu from opening and allow to modify the menu items that will be display by the current event.
-
-The `open()` callback is used to continue the context menu event and can be injected with the new modified `IShContextMenuItem` items array. (optional. if items array is not provided the original array defined by `[sh-context]` will be used.)
-
-````html
-
- Click Me !
-
+````css
+ @import "~@angular/cdk/overlay-prebuilt.css";
````
-component:
+## Usage
-````typescript
-onBefore = (event: BeforeMenuEvent) => {
- event.open([new items]);
- };
-````
+#### Defining a Basic Menu Template
-`BeforeMenuEvent` interface:
-````typescript
-interface BeforeMenuEvent {
- event: MouseEvent;
- items: IShContextMenuItem[];
- open(items?: IShContextMenuItem[]): void;
-}
-````
+The menu template is built using the `sh-context-menu` component as the menu wrapper,
+and nested `ng-template` with the `shContextMenuItem` directive for every menu item:
-### Options Object (v0.0.10)
+The `shContextMenuItem` directive provide a template variable (`let-data`) that gives you access to the data object attached to the menu.
````html
-
-````
-
-````typescript
- options: IShContextOptions = {
- // set options
- }
+
+
+
+ Menu Item - {{data.label}}
+
+
+
````
-The options object is of type `IShContextOptions` and currently support the following options:
+#### Attaching Menu To An Element
-Options | Type | Default | Description
-:---:|:---:|:---:|:---|
-rtl|boolean|false|right to left support
-theme|string|light|menu color theme
+Attaching works by using the `shAttachMenu` directive and providing the `#menu` (from the above example) template variable:
-### Sub Menus (v0.0.9)
+The object provided to the `[shMenuData]` input will be available as a template variable inside `ng-template`s with `shContextMenuItem`
-Setting the `subMenu` property to `true` and the `subMenuItems` property to a `IShContextMenuItem[]` will render a sub menu.
+```html
+
Right Click Me
+```
-````typescript
-{
- label: 'Sub Menu',
- subMenu: true,
- subMenuItems: [
- {
- label: 'Save',
- onClick: this.clickEvent
- },
- {
- label: 'Edit',
- onClick: this.clickEvent
- }]
-}
-````
-
-#### The `onClick` handler
+## Sub Menus
-The `onClick` handler is a function that is being injected with `$event` parameter.
+Sub menu is attached to the `shContextMenuItem` directive using the `[subMenu]` input.
-The `$event` structure is:
+The `[subMenu]` input is provided with a `sh-context-menu`'s template variable (just like attaching a menu to an element).
-````typescript
- {
- menuItem: item,
- dataContext: this.dataContext
- }
+````html
+
+
+
+ Menu Item - {{data.label}}
+
+
+
+
+
+ Menu Item - {{data.label}}
+
+
+
+
````
-Where the `menuItem` property is of type `IShContextMenuItem` and is the clicked menu item.
-
-And the `dataContext` is the object used on the `[sh-data-context]` binding.
+## API
+#### sh-context-menu
-#### The `disabled` and `visible` handlers
+Name | Type | Default | Description
+:---:|:---:|:---:|:---:
+[this]|any|null|the `this` context for input callbacks (visible) - typically the menu's host component
-Both get injected with the object used on the `[sh-data-context]` binding
+#### shContextMenuItem
-And should return a `boolean` to indicate if the current `IShContextMenuItem` is disabled or visible.
+Name | Type | Default | Description
+:---:|:---:|:---:|:---:
+[subMenu]|ShContextMenuComponent|null|sub menu
+[divider]|boolean|false|render a divider
+[closeOnClick]|boolean|true|should the menu close on click
+[visible]|(event: ShContextMenuClickEvent) => boolean|null|function to determine if a item is visible
+(click)|ShContextMenuClickEvent|null|click handler
### Setting up development env
diff --git a/changelog.md b/changelog.md
index 1d5e3d9..bcde96d 100644
--- a/changelog.md
+++ b/changelog.md
@@ -1,3 +1,7 @@
+### 1.0.0 - BREAKING CHANGES
+
+new api using ng-template [#fc09e66](https://github.com/msarsha/ng2-right-click-menu/commit/fc09e6687ce7ca376708386b8841d5336b3ac82a)
+
### 0.0.16
z-index increased to bring menu to foreground [#fc09e66](https://github.com/msarsha/ng2-right-click-menu/commit/fc09e6687ce7ca376708386b8841d5336b3ac82a)
diff --git a/lib/src/html.directive.ts b/lib/src/html.directive.ts
deleted file mode 100644
index 179f314..0000000
--- a/lib/src/html.directive.ts
+++ /dev/null
@@ -1,17 +0,0 @@
-import { ElementRef } from '@angular/core';
-import { AfterContentInit } from '@angular/core';
-import { Input } from '@angular/core';
-import { Directive } from '@angular/core';
-
-@Directive({
- selector: '[sh-html]'
-})
-export class HtmlDirective implements AfterContentInit {
- @Input('sh-html') content: String;
-
- constructor(private elmRef: ElementRef){}
-
- ngAfterContentInit(): void {
- this.elmRef.nativeElement.insertAdjacentHTML('afterbegin', this.content);
- }
-}
diff --git a/lib/src/index.ts b/lib/src/index.ts
deleted file mode 100644
index b1f0ff3..0000000
--- a/lib/src/index.ts
+++ /dev/null
@@ -1,2 +0,0 @@
-export { ShContextMenuModule } from './sh-context-menu.module';
-export { IShContextMenuItem, IShContextOptions, BeforeMenuEvent } from './sh-context-menu.models';
diff --git a/lib/src/injector.service.ts b/lib/src/injector.service.ts
deleted file mode 100644
index c44cfe0..0000000
--- a/lib/src/injector.service.ts
+++ /dev/null
@@ -1,129 +0,0 @@
-import {
- ApplicationRef, ComponentFactoryResolver, ComponentRef, Injectable,
- Injector, EmbeddedViewRef, Type
-} from '@angular/core';
-
-/**
- * Injection service is a helper to append components
- * dynamically to a known location in the DOM, most
- * noteably for dialogs/tooltips appending to body.
- *
- * @export
- * @class InjectionService
- */
-@Injectable()
-export class InjectionService {
- private _container: ComponentRef;
-
- constructor(
- private applicationRef: ApplicationRef,
- private componentFactoryResolver: ComponentFactoryResolver,
- private injector: Injector) {
- }
-
- /**
- * Gets the root view container to inject the component to.
- *
- * @returns {ComponentRef}
- *
- * @memberOf InjectionService
- */
- getRootViewContainer(): ComponentRef {
- if(this._container) return this._container;
-
- const rootComponents = this.applicationRef['components'];
- if (rootComponents.length) return rootComponents[0];
-
- throw new Error('View Container not found! ngUpgrade needs to manually set this via setRootViewContainer.');
- }
-
- /**
- * Overrides the default root view container. This is useful for
- * things like ngUpgrade that doesn't have a ApplicationRef root.
- *
- * @param {any} container
- *
- * @memberOf InjectionService
- */
- setRootViewContainer(container:any): void {
- this._container = container;
- }
-
- /**
- * Gets the html element for a component ref.
- *
- * @param {ComponentRef} componentRef
- * @returns {HTMLElement}
- *
- * @memberOf InjectionService
- */
- getComponentRootNode(componentRef: ComponentRef): HTMLElement {
- return (componentRef.hostView as EmbeddedViewRef).rootNodes[0] as HTMLElement;
- }
-
- /**
- * Gets the root component container html element.
- *
- * @returns {HTMLElement}
- *
- * @memberOf InjectionService
- */
- getRootViewContainerNode(): HTMLElement {
- return this.getComponentRootNode(this.getRootViewContainer());
- }
-
- /**
- * Projects the inputs onto the component
- *
- * @param {ComponentRef} component
- * @param {*} options
- * @returns {ComponentRef}
- *
- * @memberOf InjectionService
- */
- projectComponentInputs(component: ComponentRef, options: any): ComponentRef {
- if(options) {
- const props = Object.getOwnPropertyNames(options);
- for(const prop of props) {
- component.instance[prop] = options[prop];
- }
- }
-
- return component;
- }
-
- /**
- * Appends a component to a adjacent location
- *
- * @template T
- * @param {Type} componentClass
- * @param {*} [options={}]
- * @param {Element} [location=this.getRootViewContainerNode()]
- * @returns {ComponentRef}
- *
- * @memberOf InjectionService
- */
- appendComponent(
- componentClass: Type,
- options: any = {},
- location: Element = this.getRootViewContainerNode()): ComponentRef {
-
- let componentFactory = this.componentFactoryResolver.resolveComponentFactory(componentClass);
- let componentRef = componentFactory.create(this.injector);
- let appRef: any = this.applicationRef;
- let componentRootNode = this.getComponentRootNode(componentRef);
-
- // project the options passed to the component instance
- this.projectComponentInputs(componentRef, options);
-
- appRef.attachView(componentRef.hostView);
-
- componentRef.onDestroy(() => {
- appRef.detachView(componentRef.hostView);
- });
-
- location.appendChild(componentRootNode);
-
- return componentRef;
- }
-}
diff --git a/lib/src/sh-context-menu.component.ts b/lib/src/sh-context-menu.component.ts
deleted file mode 100755
index 77ec010..0000000
--- a/lib/src/sh-context-menu.component.ts
+++ /dev/null
@@ -1,197 +0,0 @@
-import {Component, Input, Output, EventEmitter, OnInit, ElementRef, ViewChild, AfterContentInit} from "@angular/core";
-import {IShContextMenuItem, IShContextOptions} from "./sh-context-menu.models";
-import {ShContextService} from './sh-context-service';
-
-export interface ShContextPosition {
- top: number;
- left: number;
-}
-
-@Component({
- selector: 'sh-context-menu',
- template: `
-
+ `
+})
+// TODO: this is not possible now (because the use of TemplatePortal instead of ComponentPortal)
+// should later define an interface for using a custom component as context menu
+export class MyMenuComponent extends ShContextMenuComponent {
+}
- clickEvent = ($event: any) => {
- console.log('clicked ', $event);
- }
+@Component({
+ selector: 'my-content',
+ template: `
+