|
1 | | -# Toppy |
| 1 | +<h1 align="center"> |
| 2 | + <br> |
| 3 | + <a href="https://lokesh-coder.github.io/toppy/"><img src="./docs/assets/toppy-logo.png" alt="Toppy" width="100"></a><br> |
| 4 | +</h1> |
2 | 5 |
|
3 | | -### Overlay library for Angular 6+ |
| 6 | +<h4 align="center">Tiny Angular library to create overlays for tooltips, modals, dropdowns, alerts, toastr, popovers, menus, and more</h4> |
4 | 7 |
|
5 | | -```shell |
6 | | -npm install toppy --save |
| 8 | +<p align="center"> |
| 9 | + <a href="https://github.com/lokesh-coder/toppy/releases"> |
| 10 | + <img src="https://img.shields.io/github/release/lokesh-coder/toppy.svg?style=flat-square&colorA=0C0B0C&colorB=2C282C" alt="Github Release"> |
| 11 | + </a> |
| 12 | + <a href="LICENSE"> |
| 13 | + <img src="https://img.shields.io/npm/l/toppy.svg?style=flat-square&colorA=0C0B0C&colorB=2C282C" alt="Licence"> |
| 14 | + </a> |
| 15 | + <a href="#"> |
| 16 | + <img src="https://img.shields.io/npm/dm/toppy.svg?style=flat-square&colorA=0C0B0C&colorB=2C282C" alt="Downloads"> |
| 17 | + </a> |
| 18 | +</p> |
| 19 | +<br> |
| 20 | + |
| 21 | +<div class="highlight highlight-source-shell"> |
| 22 | +<pre> |
| 23 | +<div align="center"><strong >Demo and documentation</strong></div> |
| 24 | +<div align="center"><a align="center" href="https://lokesh-coder.github.io/toppy/">https://lokesh-coder.github.io/toppy/</a></div> |
| 25 | +</pre> |
| 26 | +</div> |
| 27 | + |
| 28 | +### Installation |
| 29 | + |
| 30 | +**step 1:** Install from NPM or YARN |
| 31 | + |
| 32 | +```sh |
| 33 | +npm install toppy // or |
| 34 | +yarn add toppy |
| 35 | +``` |
| 36 | + |
| 37 | +**step 2:** Import `ToppyModule` in your main module |
| 38 | + |
| 39 | +```typescript |
| 40 | +import { ToppyModule } from 'toppy'; |
| 41 | + |
| 42 | +@NgModule({ |
| 43 | + declarations: [AppComponent], |
| 44 | + imports: [BrowserModule, ToppyModule], // <== |
| 45 | + bootstrap: [AppComponent] |
| 46 | +}) |
| 47 | +export class AppModule {} |
| 48 | +``` |
| 49 | + |
| 50 | +**step 3:** Import `Toppy` service in your component |
| 51 | + |
| 52 | +```typescript |
| 53 | +import { Toppy } from 'toppy'; // <== |
| 54 | + |
| 55 | +@Component({ |
| 56 | + selector: 'app-root', |
| 57 | + template: '<div #el>Click me</div>' |
| 58 | +}) |
| 59 | +export class AppComponent { |
| 60 | + @ViewChild('el', { read: ElementRef }) |
| 61 | + el: ElementRef; |
| 62 | + |
| 63 | + constructor(private _toppy: Toppy) {} |
| 64 | + |
| 65 | + ngOnInit() { |
| 66 | + const position = new RelativePosition({ |
| 67 | + placement: OutsidePlacement.BOTTOM_LEFT, |
| 68 | + src: this.el.nativeElement |
| 69 | + }); |
| 70 | + |
| 71 | + this.overlayIns = this._toppy |
| 72 | + .overlay(position) |
| 73 | + .host('hello') // content |
| 74 | + .create(); |
| 75 | + } |
| 76 | + |
| 77 | + open() { |
| 78 | + this.overlayIns.open(); |
| 79 | + } |
| 80 | + |
| 81 | + close() { |
| 82 | + this.overlayIns.close(); |
| 83 | + } |
| 84 | +} |
| 85 | +``` |
| 86 | + |
| 87 | +### Content |
| 88 | + |
| 89 | +Toppy allows to use `string`, `html`, `TemplateRef`, `Component` as overlay content. |
| 90 | + |
| 91 | +**Plain text** |
| 92 | + |
| 93 | +```typescript |
| 94 | +this.overlayIns = this._toppy |
| 95 | + .overlay(position) |
| 96 | + .host(`some plain text content`) // simple text |
| 97 | + .create(); |
| 98 | +``` |
| 99 | + |
| 100 | +**HTML content** |
| 101 | + |
| 102 | +```typescript |
| 103 | +this.overlayIns = this._toppy |
| 104 | + .overlay(position) |
| 105 | + .host(`<div>any HTML content</div>`, { hasHTML: true }) // html |
| 106 | + .create(); |
| 107 | +``` |
| 108 | + |
| 109 | +**Using TemplateRef** |
| 110 | + |
| 111 | +```html |
| 112 | +<ng-template #tpl>Hello world!</ng-template> |
| 113 | +``` |
| 114 | + |
| 115 | +```typescript |
| 116 | +@ViewChild('tpl') tpl:TemplateRef<any>; |
| 117 | + |
| 118 | +this.overlayIns = this._toppy |
| 119 | + .overlay(position) |
| 120 | + .host(this.tpl) // template ref |
| 121 | + .create(); |
| 122 | +``` |
| 123 | + |
| 124 | +**Component** |
| 125 | + |
| 126 | +```typescript |
| 127 | +// host component |
| 128 | +@Component({ |
| 129 | + template: '<div>Hello</div>' |
| 130 | +}) |
| 131 | +export class HelloComponent {} |
| 132 | +``` |
| 133 | + |
| 134 | +```typescript |
| 135 | +this.overlayIns = this._toppy |
| 136 | + .overlay(position) |
| 137 | + .host(HelloComponent) // <== |
| 138 | + .create(); |
| 139 | +``` |
| 140 | + |
| 141 | +> Dont forget to add host component in `entryComponents` in module |
| 142 | +
|
| 143 | +### Positions |
| 144 | + |
| 145 | +Position determines the location and size of the overlay. There are four positions: |
| 146 | + |
| 147 | +**Relative position** |
| 148 | + |
| 149 | +Overlay position that is relative to specific element. These are used in `tooltips`, `popovers`, `dropdowns`, `menus` |
| 150 | + |
| 151 | +```typescript |
| 152 | +new RelativePosition({ |
| 153 | + src: HTMLElement, // target element |
| 154 | + placement: OutsidePlacement, // location of the content |
| 155 | + hostWidth: string | number, // content width eg, `auto`, 150, `30%` |
| 156 | + hostHeight: string | number, // content height eg, `auto`, 150, `30%` |
| 157 | + autoUpdate: boolean // update position when window scoll/resize |
| 158 | +}); |
| 159 | +``` |
| 160 | + |
| 161 | +Relative position supports 12 placements: |
| 162 | + |
| 163 | +```typescript |
| 164 | +OutsidePlacement.BOTTOM; |
| 165 | +OutsidePlacement.BOTTOM_LEFT; |
| 166 | +OutsidePlacement.BOTTOM_RIGHT; |
| 167 | +OutsidePlacement.LEFT; |
| 168 | +OutsidePlacement.LEFT_BOTTOM; |
| 169 | +OutsidePlacement.LEFT_TOP; |
| 170 | +OutsidePlacement.RIGHT; |
| 171 | +OutsidePlacement.RIGHT_BOTTOM; |
| 172 | +OutsidePlacement.RIGHT_TOP; |
| 173 | +OutsidePlacement.TOP; |
| 174 | +OutsidePlacement.TOP_LEFT; |
| 175 | +OutsidePlacement.TOP_RIGHT; |
| 176 | +``` |
| 177 | + |
| 178 | +**Global position** |
| 179 | + |
| 180 | +Overlay position that is relative to window viewport. These are used in `modals`, `alerts`, `toastr` |
| 181 | + |
| 182 | +```typescript |
| 183 | +new GlobalPosition({ |
| 184 | + placement: InsidePlacement, // location of the content. |
| 185 | + hostWidth: string | number, // content width eg, `auto`, `150`, `30%` |
| 186 | + hostHeight: string | number, //content height eg, `auto`, 150, `30%` |
| 187 | + offset: number // oustide space of the content, in px |
| 188 | +}); |
| 189 | +``` |
| 190 | + |
| 191 | +Global position supports 9 placements: |
| 192 | + |
| 193 | +```typescript |
| 194 | +InsidePlacement.BOTTOM; |
| 195 | +InsidePlacement.BOTTOM_LEFT; |
| 196 | +InsidePlacement.BOTTOM_RIGHT; |
| 197 | +InsidePlacement.LEFT; |
| 198 | +InsidePlacement.RIGHT; |
| 199 | +InsidePlacement.TOP; |
| 200 | +InsidePlacement.TOP_LEFT; |
| 201 | +InsidePlacement.TOP_RIGHT; |
| 202 | +InsidePlacement.CENTER; |
7 | 203 | ``` |
| 204 | + |
| 205 | +**Slide position** |
| 206 | + |
| 207 | +Overlay position that is relative to window viewport. These are used in `side panels`, `sidebars`, `blade` |
| 208 | + |
| 209 | +```typescript |
| 210 | +new SlidePosition({ |
| 211 | + placement: SlidePlacement, // rigth or left |
| 212 | + width: string // width eg, '300px' or '30%' |
| 213 | +}); |
| 214 | +``` |
| 215 | + |
| 216 | +Slide position supports 2 placements: |
| 217 | + |
| 218 | +```typescript |
| 219 | +SlidePlacement.LEFT; |
| 220 | +SlidePlacement.RIGHT; |
| 221 | +``` |
| 222 | + |
| 223 | +**Fullscreen position** |
| 224 | + |
| 225 | +Overlay that occupies complete size of the viewport. |
| 226 | + |
| 227 | +```typescript |
| 228 | +new FullScreenPosition(); |
| 229 | +``` |
| 230 | + |
| 231 | +### Configuration |
| 232 | + |
| 233 | +```typescript |
| 234 | +this.toppy |
| 235 | + .overlay(position, configuration) |
| 236 | + .host('hello') |
| 237 | + .create(); |
| 238 | +``` |
| 239 | + |
| 240 | +| `property` | `default` | `supported values` | |
| 241 | +| -------------------------- | ------------------- | ------------------ | |
| 242 | +| **backdrop** | _false_ | boolean | |
| 243 | +| **containerClass** | _'toppy-container'_ | string | |
| 244 | +| **wrapperClass** | _'toppy-wrapper'_ | string | |
| 245 | +| **backdropClass** | _'toppy-backdrop'_ | string | |
| 246 | +| **bodyClassNameOnOpen** | _''_ | string | |
| 247 | +| **dismissOnDocumentClick** | _true_ | boolean | |
| 248 | +| **closeOnEsc** | _false_ | boolean | |
| 249 | +| **parentElement** | _null_ | HTMLElement | |
| 250 | +| **watchDocClick** | _true_ | boolean | |
| 251 | +| **watchWindowResize** | _true_ | boolean | |
| 252 | +| **windowResizeCallback** | _null_ | function | |
| 253 | +| **docClickCallback** | _null_ | function | |
| 254 | + |
| 255 | +### Component communication |
| 256 | + |
| 257 | +When you host a component, you can control the overlay through `CurrentOverlay` service. As of now, this service has only one method called `close` to close the overlay from the host component. But, soon more API will be added to this service. |
| 258 | + |
| 259 | +```typescript |
| 260 | +// host component |
| 261 | +@Component({ |
| 262 | + template: '<div>Some text</div>' |
| 263 | +}) |
| 264 | +export class HostComponent { |
| 265 | + constructor(private _overlay: CurrentOverlay) {} |
| 266 | + |
| 267 | + close() { |
| 268 | + this._overlay.close(); |
| 269 | + } |
| 270 | +} |
| 271 | +``` |
| 272 | + |
| 273 | +You can also set properties to component when creating the overlay. |
| 274 | + |
| 275 | +```typescript |
| 276 | +this.overlayIns = this._toppy |
| 277 | + .overlay(position) |
| 278 | + .host(HelloComponent, { propName: 'toppy-test-prop' }) |
| 279 | + .create(); |
| 280 | +``` |
| 281 | + |
| 282 | +Now automatically all props are attached to host component and you can access it like, |
| 283 | + |
| 284 | +```typescript |
| 285 | +// host component |
| 286 | +@Component({ |
| 287 | + template: '<div>Some text</div>' |
| 288 | +}) |
| 289 | +export class HostComponent { |
| 290 | + propName; // else tslint will throw error |
| 291 | + constructor() { |
| 292 | + console.log(this.propName); // will return 'toppy-test-prop' |
| 293 | + } |
| 294 | +} |
| 295 | +``` |
| 296 | + |
| 297 | +### API |
| 298 | + |
| 299 | +> ```typescript |
| 300 | +> Toppy.overlay(position:Position, config:ToppyConfig):Toppy |
| 301 | +> ``` |
| 302 | +
|
| 303 | +> ```typescript |
| 304 | +> Toppy.host( |
| 305 | +> content: string | TemplateRef<any> | ComponentType<any>, |
| 306 | +> props: { [x: string]: any } = {} |
| 307 | +> ):Toppy |
| 308 | +> ``` |
| 309 | +
|
| 310 | +> ```typescript |
| 311 | +> Toppy.create(position:Position, config:ToppyConfig):ToppyRef |
| 312 | +> ``` |
| 313 | +
|
| 314 | +--- |
| 315 | +
|
| 316 | +> ```typescript |
| 317 | +> ToppyRef.open():void |
| 318 | +> ``` |
| 319 | +
|
| 320 | +> ```typescript |
| 321 | +> ToppyRef.close():void |
| 322 | +> ``` |
| 323 | +
|
| 324 | +> ```typescript |
| 325 | +> ToppyRef.toggle():void |
| 326 | +> ``` |
| 327 | +
|
| 328 | +> ```typescript |
| 329 | +> ToppyRef.onDocumentClick():Observable |
| 330 | +> ``` |
| 331 | +
|
| 332 | +> ```typescript |
| 333 | +> ToppyRef.onWindowResize():Observable |
| 334 | +> ``` |
| 335 | +
|
| 336 | +> ```typescript |
| 337 | +> ToppyRef.getConfig():ToppyConfig |
| 338 | +> ``` |
| 339 | +
|
| 340 | +> ```typescript |
| 341 | +> ToppyRef.updateHost( |
| 342 | +> content: string | TemplateRef<any> | ComponentType<any>, |
| 343 | +> props: { [x: string]: any } = {} |
| 344 | +> ):ToppyRef |
| 345 | +> ``` |
| 346 | +
|
| 347 | +> ```typescript |
| 348 | +> ToppyRef.updatePosition(config:object):ToppyRef |
| 349 | +> ``` |
| 350 | +
|
| 351 | +### Contribution |
| 352 | +
|
| 353 | +Any kind of contributions ( Typo fix, documentation, code quality, performance, refactor, pipeline, etc., ) are welcome. :) |
| 354 | +
|
| 355 | +### Issues |
| 356 | +
|
| 357 | +Found a bug? Have some idea? Or do you have questions? File it [here](https://github.com/lokesh-coder/toppy/issues) |
| 358 | +
|
| 359 | +### Licence |
| 360 | +
|
| 361 | +MIT |
0 commit comments