ng-hub-ui-board 19.2.0 → 19.3.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.npmignore +2 -0
- package/README.md +43 -22
- package/fesm2022/ng-hub-ui-board.mjs +253 -91
- package/fesm2022/ng-hub-ui-board.mjs.map +1 -1
- package/index.d.ts +392 -3
- package/ng-hub-ui-board-19.3.1.tgz +0 -0
- package/package.json +64 -21
- package/lib/board.module.d.ts +0 -10
- package/lib/components/board/board.component.d.ts +0 -51
- package/lib/directives/board-column-footer.directive.d.ts +0 -8
- package/lib/directives/board-column-header.directive.d.ts +0 -8
- package/lib/directives/card-template.directive.d.ts +0 -8
- package/lib/models/board-card.d.ts +0 -12
- package/lib/models/board-column.d.ts +0 -58
- package/lib/models/board.d.ts +0 -34
- package/lib/models/reached-end-event.d.ts +0 -8
- package/lib/pipes/invert-color.pipe.d.ts +0 -7
- package/ng-hub-ui-board-19.2.0.tgz +0 -0
- package/public-api.d.ts +0 -10
- package/src/lib/styles/base.scss +0 -206
package/.npmignore
ADDED
package/README.md
CHANGED
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
|
|
7
7
|
This component is part of the ng-hub-ui ecosystem, which includes:
|
|
8
8
|
|
|
9
|
-
- [ng-hub-ui-
|
|
9
|
+
- [ng-hub-ui-paginable](https://www.npmjs.com/package/ng-hub-ui-paginable)
|
|
10
10
|
- [ng-hub-ui-modal](https://www.npmjs.com/package/ng-hub-ui-modal)
|
|
11
11
|
- [ng-hub-ui-stepper](https://www.npmjs.com/package/ng-hub-ui-stepper)
|
|
12
12
|
- [ng-hub-ui-breadcrumbs](https://www.npmjs.com/package/ng-hub-ui-breadcrumbs)
|
|
@@ -20,14 +20,16 @@ A flexible and powerful board component for Angular applications, perfect for im
|
|
|
20
20
|
|
|
21
21
|
## Features
|
|
22
22
|
|
|
23
|
-
- 🎯 Standalone component
|
|
24
|
-
- 🔄 Drag and drop support for both cards and columns
|
|
25
|
-
- 📱 Responsive design
|
|
26
|
-
- 🎨 Highly customizable
|
|
27
|
-
- 🔧 Bootstrap compatible
|
|
28
|
-
- ⚡ Virtual scrolling
|
|
29
|
-
- 🎭 Custom styling
|
|
30
|
-
- 🔒
|
|
23
|
+
- 🎯 **Standalone component** - Modern Angular approach with minimal setup
|
|
24
|
+
- 🔄 **Drag and drop support** - Full drag-and-drop for both cards and columns using Angular CDK
|
|
25
|
+
- 📱 **Responsive design** - Works seamlessly across desktop, tablet, and mobile devices
|
|
26
|
+
- 🎨 **Highly customizable** - Custom templates for cards, headers, and footers
|
|
27
|
+
- 🔧 **Bootstrap compatible** - Integrates perfectly with Bootstrap 5 design system
|
|
28
|
+
- ⚡ **Virtual scrolling** - Supports infinite scroll with end-detection for performance
|
|
29
|
+
- 🎭 **Custom styling** - CSS custom properties for easy theming and customization
|
|
30
|
+
- 🔒 **Granular control** - Enable/disable functionality at board, column, or card level
|
|
31
|
+
- 🏷️ **TypeScript support** - Full type safety with generic interfaces
|
|
32
|
+
- ♿ **Accessibility ready** - Follows WAI-ARIA best practices for drag-and-drop
|
|
31
33
|
|
|
32
34
|
## Installation
|
|
33
35
|
|
|
@@ -114,7 +116,7 @@ export class BoardDemoComponent {
|
|
|
114
116
|
</hub-board>
|
|
115
117
|
```
|
|
116
118
|
|
|
117
|
-
|
|
119
|
+
This code block provides a minimal and functional example for both beginners and intermediate users.
|
|
118
120
|
|
|
119
121
|
## Usage
|
|
120
122
|
|
|
@@ -261,7 +263,7 @@ handleCardMoved(event: CdkDragDrop<BoardColumn, BoardColumn, BoardCard>) {
|
|
|
261
263
|
Emitted when a column is reordered via drag and drop.
|
|
262
264
|
|
|
263
265
|
```html
|
|
264
|
-
<hub-board [board]="board" (
|
|
266
|
+
<hub-board [board]="board" (onColumnMoved)="handleColumnMoved($event)"> </hub-board>
|
|
265
267
|
```
|
|
266
268
|
|
|
267
269
|
**Type:** `EventEmitter<CdkDragDrop<BoardColumn[]>>`
|
|
@@ -471,23 +473,42 @@ Each case benefits from customizable columns, card templates, and event outputs
|
|
|
471
473
|
Here are some common issues and how to resolve them:
|
|
472
474
|
|
|
473
475
|
### 🔄 Drag and drop not working
|
|
474
|
-
|
|
476
|
+
- **Check dependencies**: Ensure `@angular/cdk` is installed and imported
|
|
477
|
+
- **Reactive data**: Verify your board data is reactive (using `signal()`, `Observable`, or proper change detection)
|
|
478
|
+
- **Browser compatibility**: Ensure your target browsers support the HTML5 Drag and Drop API
|
|
475
479
|
|
|
476
480
|
### 📏 Scroll detection not triggering `reachedEnd`
|
|
477
|
-
|
|
481
|
+
- **Height constraints**: The `<hub-board>` element or its parent must have a `max-height` or fixed height
|
|
482
|
+
- **Overflow setting**: Ensure `overflow: auto` or `overflow-y: scroll` is applied to enable scrolling
|
|
483
|
+
- **Content length**: Make sure there's enough content to actually trigger scrolling
|
|
478
484
|
|
|
479
485
|
### 🎨 Styles not applying
|
|
480
|
-
Confirm you've imported the SCSS base styles in your global `styles.scss`:
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
486
|
+
- **Import path**: Confirm you've imported the SCSS base styles in your global `styles.scss`:
|
|
487
|
+
```scss
|
|
488
|
+
@use '../dist/board/src/lib/styles/base.scss' as boardBase;
|
|
489
|
+
```
|
|
490
|
+
- **CSS custom properties**: Check that your custom CSS variables follow the `--hub-*` naming convention
|
|
491
|
+
- **Style specificity**: Ensure your custom styles have sufficient specificity to override defaults
|
|
485
492
|
|
|
486
493
|
### 🧩 Templates not rendering
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
494
|
+
- **Import directives**: When using standalone components, import the template directives:
|
|
495
|
+
```typescript
|
|
496
|
+
imports: [HubBoardComponent, CardTemplateDirective, BoardColumnHeaderDirective]
|
|
497
|
+
```
|
|
498
|
+
- **Template syntax**: Verify you're using the correct template selectors (`cardTpt`, `columnHeaderTpt`, `columnFooterTpt`)
|
|
499
|
+
|
|
500
|
+
### 🛠️ Runtime errors
|
|
501
|
+
- **"Cannot read property 'cards' of undefined"**: Initialize your board signal properly:
|
|
502
|
+
```typescript
|
|
503
|
+
board = signal<Board>({ title: 'My Board', columns: [] });
|
|
504
|
+
```
|
|
505
|
+
- **Type errors**: Ensure your data matches the `Board`, `BoardColumn`, and `BoardCard` interfaces
|
|
506
|
+
- **Signal updates**: Use `.set()` or `.update()` methods to modify signal values
|
|
507
|
+
|
|
508
|
+
### 🎯 Performance issues
|
|
509
|
+
- **Large datasets**: Consider implementing virtual scrolling for columns with many cards
|
|
510
|
+
- **Memory leaks**: Ensure proper cleanup of event listeners and subscriptions
|
|
511
|
+
- **Change detection**: Use `OnPush` change detection strategy when possible
|
|
491
512
|
|
|
492
513
|
If problems persist, open an issue at: https://github.com/carlos-morcillo/ng-hub-ui-board/issues
|
|
493
514
|
|
|
@@ -1,17 +1,45 @@
|
|
|
1
1
|
import * as i0 from '@angular/core';
|
|
2
|
-
import { Directive, input, computed, contentChild, TemplateRef,
|
|
2
|
+
import { Directive, input, computed, contentChild, TemplateRef, output, Component, NgModule, Pipe } from '@angular/core';
|
|
3
3
|
import * as i1 from '@angular/cdk/drag-drop';
|
|
4
4
|
import { moveItemInArray, transferArrayItem, DragDropModule } from '@angular/cdk/drag-drop';
|
|
5
5
|
import { NgClass, NgStyle, NgTemplateOutlet } from '@angular/common';
|
|
6
6
|
|
|
7
|
+
/**
|
|
8
|
+
* Directive that allows customization of column footer templates within board columns.
|
|
9
|
+
*
|
|
10
|
+
* This directive enables developers to define custom templates for column footers,
|
|
11
|
+
* perfect for displaying summary information, quick actions, statistics,
|
|
12
|
+
* or any column-specific controls at the bottom of each column.
|
|
13
|
+
*
|
|
14
|
+
* @publicApi
|
|
15
|
+
*
|
|
16
|
+
* @example
|
|
17
|
+
* ```html
|
|
18
|
+
* <ng-template columnFooterTpt let-column="column">
|
|
19
|
+
* <div class="custom-footer">
|
|
20
|
+
* <div class="column-summary">
|
|
21
|
+
* <span>Total: {{ column.cards.length }}</span>
|
|
22
|
+
* <span>Priority Items: {{ getPriorityItems(column) }}</span>
|
|
23
|
+
* </div>
|
|
24
|
+
* <button (click)="quickAddCard(column)">Quick Add</button>
|
|
25
|
+
* </div>
|
|
26
|
+
* </ng-template>
|
|
27
|
+
* ```
|
|
28
|
+
*/
|
|
7
29
|
class BoardColumnFooterDirective {
|
|
30
|
+
templateRef;
|
|
31
|
+
/**
|
|
32
|
+
* Creates a new BoardColumnFooterDirective instance.
|
|
33
|
+
*
|
|
34
|
+
* @param templateRef - The template reference that contains the custom column footer layout
|
|
35
|
+
*/
|
|
8
36
|
constructor(templateRef) {
|
|
9
37
|
this.templateRef = templateRef;
|
|
10
38
|
}
|
|
11
|
-
static
|
|
12
|
-
static
|
|
39
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.2.3", ngImport: i0, type: BoardColumnFooterDirective, deps: [{ token: i0.TemplateRef }], target: i0.ɵɵFactoryTarget.Directive });
|
|
40
|
+
static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "20.2.3", type: BoardColumnFooterDirective, isStandalone: true, selector: "[columnFooterTpt]", ngImport: i0 });
|
|
13
41
|
}
|
|
14
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "
|
|
42
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.2.3", ngImport: i0, type: BoardColumnFooterDirective, decorators: [{
|
|
15
43
|
type: Directive,
|
|
16
44
|
args: [{
|
|
17
45
|
selector: '[columnFooterTpt]',
|
|
@@ -19,14 +47,40 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.8", ngImpor
|
|
|
19
47
|
}]
|
|
20
48
|
}], ctorParameters: () => [{ type: i0.TemplateRef }] });
|
|
21
49
|
|
|
50
|
+
/**
|
|
51
|
+
* Directive that allows customization of column header templates within board columns.
|
|
52
|
+
*
|
|
53
|
+
* This directive provides the ability to define custom templates for rendering column headers,
|
|
54
|
+
* giving developers full control over the appearance and functionality of column headers
|
|
55
|
+
* including titles, descriptions, actions, and metadata display.
|
|
56
|
+
*
|
|
57
|
+
* @publicApi
|
|
58
|
+
*
|
|
59
|
+
* @example
|
|
60
|
+
* ```html
|
|
61
|
+
* <ng-template columnHeaderTpt let-column="column">
|
|
62
|
+
* <div class="custom-header">
|
|
63
|
+
* <h2>{{ column.title }}</h2>
|
|
64
|
+
* <span class="card-count">{{ column.cards.length }} items</span>
|
|
65
|
+
* <button (click)="addCard(column)">Add Card</button>
|
|
66
|
+
* </div>
|
|
67
|
+
* </ng-template>
|
|
68
|
+
* ```
|
|
69
|
+
*/
|
|
22
70
|
class BoardColumnHeaderDirective {
|
|
71
|
+
templateRef;
|
|
72
|
+
/**
|
|
73
|
+
* Creates a new BoardColumnHeaderDirective instance.
|
|
74
|
+
*
|
|
75
|
+
* @param templateRef - The template reference that contains the custom column header layout
|
|
76
|
+
*/
|
|
23
77
|
constructor(templateRef) {
|
|
24
78
|
this.templateRef = templateRef;
|
|
25
79
|
}
|
|
26
|
-
static
|
|
27
|
-
static
|
|
80
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.2.3", ngImport: i0, type: BoardColumnHeaderDirective, deps: [{ token: i0.TemplateRef }], target: i0.ɵɵFactoryTarget.Directive });
|
|
81
|
+
static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "20.2.3", type: BoardColumnHeaderDirective, isStandalone: true, selector: "[columnHeaderTpt]", ngImport: i0 });
|
|
28
82
|
}
|
|
29
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "
|
|
83
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.2.3", ngImport: i0, type: BoardColumnHeaderDirective, decorators: [{
|
|
30
84
|
type: Directive,
|
|
31
85
|
args: [{
|
|
32
86
|
selector: '[columnHeaderTpt]',
|
|
@@ -34,14 +88,39 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.8", ngImpor
|
|
|
34
88
|
}]
|
|
35
89
|
}], ctorParameters: () => [{ type: i0.TemplateRef }] });
|
|
36
90
|
|
|
91
|
+
/**
|
|
92
|
+
* Directive that allows customization of card templates within board columns.
|
|
93
|
+
*
|
|
94
|
+
* This directive is used to define custom templates for rendering board cards.
|
|
95
|
+
* It provides access to the template reference that can be used by the board component
|
|
96
|
+
* to render cards with custom layouts and styling.
|
|
97
|
+
*
|
|
98
|
+
* @publicApi
|
|
99
|
+
*
|
|
100
|
+
* @example
|
|
101
|
+
* ```html
|
|
102
|
+
* <ng-template cardTpt let-card="item" let-column="column">
|
|
103
|
+
* <div class="custom-card">
|
|
104
|
+
* <h3>{{ card.title }}</h3>
|
|
105
|
+
* <p>{{ card.description }}</p>
|
|
106
|
+
* </div>
|
|
107
|
+
* </ng-template>
|
|
108
|
+
* ```
|
|
109
|
+
*/
|
|
37
110
|
class CardTemplateDirective {
|
|
111
|
+
templateRef;
|
|
112
|
+
/**
|
|
113
|
+
* Creates a new CardTemplateDirective instance.
|
|
114
|
+
*
|
|
115
|
+
* @param templateRef - The template reference that contains the custom card layout
|
|
116
|
+
*/
|
|
38
117
|
constructor(templateRef) {
|
|
39
118
|
this.templateRef = templateRef;
|
|
40
119
|
}
|
|
41
|
-
static
|
|
42
|
-
static
|
|
120
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.2.3", ngImport: i0, type: CardTemplateDirective, deps: [{ token: i0.TemplateRef }], target: i0.ɵɵFactoryTarget.Directive });
|
|
121
|
+
static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "20.2.3", type: CardTemplateDirective, isStandalone: true, selector: "[cardTpt]", ngImport: i0 });
|
|
43
122
|
}
|
|
44
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "
|
|
123
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.2.3", ngImport: i0, type: CardTemplateDirective, decorators: [{
|
|
45
124
|
type: Directive,
|
|
46
125
|
args: [{
|
|
47
126
|
selector: '[cardTpt]',
|
|
@@ -49,115 +128,179 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.8", ngImpor
|
|
|
49
128
|
}]
|
|
50
129
|
}], ctorParameters: () => [{ type: i0.TemplateRef }] });
|
|
51
130
|
|
|
131
|
+
/**
|
|
132
|
+
* Standalone Kanban-style board component that provides column-based drag-and-drop,
|
|
133
|
+
* custom templates and infinite-scroll detection.
|
|
134
|
+
*
|
|
135
|
+
* @publicApi
|
|
136
|
+
*/
|
|
52
137
|
class HubBoardComponent {
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
138
|
+
/**
|
|
139
|
+
* Reactive input containing the full board definition (columns and cards).
|
|
140
|
+
*/
|
|
141
|
+
board = input(...(ngDevMode ? [undefined, { debugName: "board" }] : []));
|
|
142
|
+
/**
|
|
143
|
+
* Pixel threshold used when determining whether a column has reached scroll end.
|
|
144
|
+
* Allows for fractional scroll values across different browsers.
|
|
145
|
+
*/
|
|
146
|
+
scrollDetectionPadding = 1;
|
|
147
|
+
/**
|
|
148
|
+
* Derived list of board columns exposed as a signal to the template.
|
|
149
|
+
*/
|
|
150
|
+
columns = computed(() => {
|
|
151
|
+
return this.board()?.columns ?? [];
|
|
152
|
+
}, ...(ngDevMode ? [{ debugName: "columns" }] : []));
|
|
153
|
+
/**
|
|
154
|
+
* When true, column reordering via drag-and-drop is disabled.
|
|
155
|
+
*/
|
|
156
|
+
columnSortingDisabled = input(false, ...(ngDevMode ? [{ debugName: "columnSortingDisabled" }] : []));
|
|
157
|
+
/**
|
|
158
|
+
* Custom card template supplied via the `cardTpt` structural directive.
|
|
159
|
+
*/
|
|
160
|
+
cardTpt = contentChild(CardTemplateDirective, ...(ngDevMode ? [{ debugName: "cardTpt", read: (TemplateRef) }] : [{
|
|
62
161
|
read: (TemplateRef)
|
|
63
|
-
});
|
|
64
|
-
|
|
65
|
-
|
|
162
|
+
}]));
|
|
163
|
+
/**
|
|
164
|
+
* Custom column header template supplied via the `columnHeaderTpt` structural directive.
|
|
165
|
+
*/
|
|
166
|
+
columnHeaderTpt = contentChild(BoardColumnHeaderDirective, ...(ngDevMode ? [{ debugName: "columnHeaderTpt", read: (TemplateRef) }] : [{
|
|
66
167
|
read: (TemplateRef)
|
|
67
|
-
});
|
|
68
|
-
|
|
69
|
-
|
|
168
|
+
}]));
|
|
169
|
+
/**
|
|
170
|
+
* Custom column footer template supplied via the `columnFooterTpt` structural directive.
|
|
171
|
+
*/
|
|
172
|
+
columnFooterTpt = contentChild(BoardColumnFooterDirective, ...(ngDevMode ? [{ debugName: "columnFooterTpt", read: (TemplateRef) }] : [{
|
|
70
173
|
read: (TemplateRef)
|
|
71
|
-
});
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
174
|
+
}]));
|
|
175
|
+
/**
|
|
176
|
+
* Emits each time a card is clicked within the board.
|
|
177
|
+
*/
|
|
178
|
+
onCardClick = output();
|
|
179
|
+
/**
|
|
180
|
+
* Emits when a card has been repositioned, either within the same column or into another column.
|
|
181
|
+
*/
|
|
182
|
+
onCardMoved = output();
|
|
183
|
+
/**
|
|
184
|
+
* Emits when columns are reordered through drag-and-drop.
|
|
185
|
+
*/
|
|
186
|
+
onColumnMoved = output();
|
|
187
|
+
/**
|
|
188
|
+
* Emits when a column body is scrolled to its end, enabling infinite-scroll behaviour.
|
|
189
|
+
*/
|
|
190
|
+
reachedEnd = output();
|
|
83
191
|
/**
|
|
84
|
-
*
|
|
192
|
+
* Default predicate that allows any card to be dropped into any column.
|
|
85
193
|
*
|
|
86
|
-
* @
|
|
194
|
+
* @returns Always `true`, indicating that drop operations are permitted.
|
|
195
|
+
*/
|
|
196
|
+
defaultEnterPredicateFn = () => true;
|
|
197
|
+
/**
|
|
198
|
+
* Emits the clicked card through {@link onCardClick}.
|
|
199
|
+
*
|
|
200
|
+
* @param item - The card that triggered the click event.
|
|
87
201
|
*/
|
|
88
202
|
cardClick(item) {
|
|
89
|
-
this.onCardClick.
|
|
203
|
+
this.onCardClick.emit(item);
|
|
90
204
|
}
|
|
91
205
|
/**
|
|
92
|
-
*
|
|
93
|
-
* emits an event.
|
|
206
|
+
* Updates column order when a drag-and-drop operation completes and emits the resulting event.
|
|
94
207
|
*
|
|
95
|
-
* @param event -
|
|
208
|
+
* @param event - Drag-and-drop metadata describing the column movement.
|
|
96
209
|
*/
|
|
97
210
|
dropColumn(event) {
|
|
98
211
|
moveItemInArray(event.container.data, event.previousIndex, event.currentIndex);
|
|
99
212
|
this.onColumnMoved.emit(event);
|
|
100
213
|
}
|
|
101
214
|
/**
|
|
102
|
-
*
|
|
103
|
-
*
|
|
215
|
+
* Applies card reordering or transfer logic depending on the drag-drop target,
|
|
216
|
+
* then emits the corresponding drag event metadata.
|
|
104
217
|
*
|
|
105
|
-
* @param event -
|
|
218
|
+
* @param event - Drag-and-drop metadata describing the card movement.
|
|
106
219
|
*/
|
|
107
220
|
dropCard(event) {
|
|
108
221
|
if (event.previousContainer === event.container) {
|
|
222
|
+
// Reorder the card within the same column
|
|
109
223
|
moveItemInArray(event.container.data.cards, event.previousIndex, event.currentIndex);
|
|
110
224
|
}
|
|
111
225
|
else {
|
|
226
|
+
// Transfer the card from one column to another
|
|
112
227
|
transferArrayItem(event.previousContainer.data.cards, event.container.data.cards, event.previousIndex, event.currentIndex);
|
|
113
228
|
}
|
|
114
229
|
this.onCardMoved.emit(event);
|
|
115
230
|
}
|
|
116
231
|
/**
|
|
117
|
-
*
|
|
232
|
+
* Emits {@link reachedEnd} once a column body is scrolled to its bottom.
|
|
118
233
|
*
|
|
119
|
-
* @param
|
|
120
|
-
* @param
|
|
121
|
-
* scroll event, such as the source element that triggered the event, the amount of scrolling that has occurred, and the dimensions
|
|
122
|
-
* of the scrollable area.
|
|
234
|
+
* @param index - Index of the scrolled column within the board.
|
|
235
|
+
* @param event - Browser scroll event originating from the column body element.
|
|
123
236
|
*/
|
|
124
237
|
onScroll(index, event) {
|
|
125
238
|
const el = event.target;
|
|
126
|
-
if (el
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
239
|
+
if (!el) {
|
|
240
|
+
return;
|
|
241
|
+
}
|
|
242
|
+
const scrolledToBottom = el.scrollTop + el.clientHeight >= el.scrollHeight - this.scrollDetectionPadding;
|
|
243
|
+
if (!scrolledToBottom) {
|
|
244
|
+
return;
|
|
131
245
|
}
|
|
246
|
+
const column = this.board()?.columns?.[index];
|
|
247
|
+
if (!column) {
|
|
248
|
+
return;
|
|
249
|
+
}
|
|
250
|
+
this.reachedEnd.emit({
|
|
251
|
+
index,
|
|
252
|
+
data: column
|
|
253
|
+
});
|
|
132
254
|
}
|
|
133
|
-
static
|
|
134
|
-
static
|
|
255
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.2.3", ngImport: i0, type: HubBoardComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
256
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.2.3", type: HubBoardComponent, isStandalone: true, selector: "hub-board, hub-ui-board", inputs: { board: { classPropertyName: "board", publicName: "board", isSignal: true, isRequired: false, transformFunction: null }, columnSortingDisabled: { classPropertyName: "columnSortingDisabled", publicName: "columnSortingDisabled", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { onCardClick: "onCardClick", onCardMoved: "onCardMoved", onColumnMoved: "onColumnMoved", reachedEnd: "reachedEnd" }, queries: [{ propertyName: "cardTpt", first: true, predicate: CardTemplateDirective, descendants: true, read: TemplateRef, isSignal: true }, { propertyName: "columnHeaderTpt", first: true, predicate: BoardColumnHeaderDirective, descendants: true, read: TemplateRef, isSignal: true }, { propertyName: "columnFooterTpt", first: true, predicate: BoardColumnFooterDirective, descendants: true, read: TemplateRef, isSignal: true }], ngImport: i0, template: "@if (columns().length) {\n\t<div\n\t\tclass=\"hub-board\"\n\t\tcdkDropList\n\t\tcdkDropListOrientation=\"horizontal\"\n\t\t[cdkDropListData]=\"columns()\"\n\t\t(cdkDropListDropped)=\"dropColumn($event)\"\n\t\t[cdkDropListSortingDisabled]=\"columnSortingDisabled()\"\n\t>\n\t\t<div cdkDropListGroup class=\"hub-board__columns\">\n\t\t\t@for (column of columns(); let index = $index; track column) {\n\t\t\t\t<div\n\t\t\t\t\tclass=\"hub-board__column-container\"\n\t\t\t\t\tcdkDrag\n\t\t\t\t\t[cdkDragData]=\"column\"\n\t\t\t\t\t[cdkDragDisabled]=\"column.disabled\"\n\t\t\t\t>\n\t\t\t\t\t<div\n\t\t\t\t\t\tclass=\"hub-board__column\"\n\t\t\t\t\t\t[ngClass]=\"column.classlist\"\n\t\t\t\t\t\t[ngStyle]=\"column.style\"\n\t\t\t\t\t>\n\t\t\t\t\t\t<div class=\"hub-board__column-header\">\n\t\t\t\t\t\t\t<ng-container\n\t\t\t\t\t\t\t\t[ngTemplateOutlet]=\"\n\t\t\t\t\t\t\t\t\tcolumnHeaderTpt() || defaultColumnHeaderTpt\n\t\t\t\t\t\t\t\t\"\n\t\t\t\t\t\t\t\t[ngTemplateOutletContext]=\"{ column: column }\"\n\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t</ng-container>\n\t\t\t\t\t\t</div>\n\t\t\t\t\t\t<div\n\t\t\t\t\t\t\tclass=\"hub-board__column-body\"\n\t\t\t\t\t\t\tcdkDropList\n\t\t\t\t\t\t\t[cdkDropListData]=\"column\"\n\t\t\t\t\t\t\t(cdkDropListDropped)=\"dropCard($event)\"\n\t\t\t\t\t\t\t(scroll)=\"onScroll(index, $event)\"\n\t\t\t\t\t\t\t[cdkDropListEnterPredicate]=\"\n\t\t\t\t\t\t\t\tcolumn.predicate ?? defaultEnterPredicateFn\n\t\t\t\t\t\t\t\"\n\t\t\t\t\t\t\t[cdkDropListSortingDisabled]=\"\n\t\t\t\t\t\t\t\tcolumn.cardSortingDisabled\n\t\t\t\t\t\t\t\"\n\t\t\t\t\t\t>\n\t\t\t\t\t\t\t@for (\n\t\t\t\t\t\t\t\tcard of column.cards;\n\t\t\t\t\t\t\t\tlet index = $index;\n\t\t\t\t\t\t\t\ttrack card\n\t\t\t\t\t\t\t) {\n\t\t\t\t\t\t\t\t<div\n\t\t\t\t\t\t\t\t\tclass=\"hub-board__card\"\n\t\t\t\t\t\t\t\t\t[class.hub-board__card--disabled]=\"\n\t\t\t\t\t\t\t\t\t\tcard.disabled\n\t\t\t\t\t\t\t\t\t\"\n\t\t\t\t\t\t\t\t\tcdkDrag\n\t\t\t\t\t\t\t\t\t[cdkDragData]=\"card\"\n\t\t\t\t\t\t\t\t\t[cdkDragDisabled]=\"card.disabled\"\n\t\t\t\t\t\t\t\t\t(click)=\"cardClick(card)\"\n\t\t\t\t\t\t\t\t\t(mousedown)=\"\n\t\t\t\t\t\t\t\t\t\tcard.disabled &&\n\t\t\t\t\t\t\t\t\t\t\t$event.stopPropagation()\n\t\t\t\t\t\t\t\t\t\"\n\t\t\t\t\t\t\t\t\t[ngClass]=\"card.classlist\"\n\t\t\t\t\t\t\t\t\t[ngStyle]=\"card.style\"\n\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t<div class=\"hub-board__card-body\">\n\t\t\t\t\t\t\t\t\t\t<ng-container\n\t\t\t\t\t\t\t\t\t\t\t[ngTemplateOutlet]=\"\n\t\t\t\t\t\t\t\t\t\t\t\tcardTpt() || defaultCardTpt\n\t\t\t\t\t\t\t\t\t\t\t\"\n\t\t\t\t\t\t\t\t\t\t\t[ngTemplateOutletContext]=\"{\n\t\t\t\t\t\t\t\t\t\t\t\titem: card,\n\t\t\t\t\t\t\t\t\t\t\t\tcolumn\n\t\t\t\t\t\t\t\t\t\t\t}\"\n\t\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t</ng-container>\n\t\t\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t</div>\n\n\t\t\t\t\t\t@if (columnFooterTpt()) {\n\t\t\t\t\t\t\t<div class=\"hub-board__column-footer\">\n\t\t\t\t\t\t\t\t<ng-container\n\t\t\t\t\t\t\t\t\t[ngTemplateOutlet]=\"\n\t\t\t\t\t\t\t\t\t\tcolumnFooterTpt() ?? null\n\t\t\t\t\t\t\t\t\t\"\n\t\t\t\t\t\t\t\t\t[ngTemplateOutletContext]=\"{\n\t\t\t\t\t\t\t\t\t\tcolumn: column\n\t\t\t\t\t\t\t\t\t}\"\n\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t</ng-container>\n\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t}\n\t\t\t\t\t</div>\n\t\t\t\t</div>\n\t\t\t}\n\t\t</div>\n\t</div>\n}\n\n<ng-template #defaultCardTpt let-item=\"item\">\n\t<h6>{{ item.title }}</h6>\n\t<p class=\"card-text\">{{ item.description }}</p>\n</ng-template>\n\n<ng-template #defaultColumnHeaderTpt let-column=\"column\">\n\t<div class=\"d-flex flex-column\">\n\t\t<h5 class=\"hub-board__column-header-title\">\n\t\t\t{{ column.title }}\n\t\t</h5>\n\t\t<h6 class=\"hub-board__column-header-subtitle\">\n\t\t\t{{ column.description }}\n\t\t</h6>\n\t</div>\n</ng-template>\n", styles: [":host{display:block;overflow:auto;width:100%;height:100%}.hub-board__column-body{min-height:128px}.cdk-drag-preview{box-sizing:border-box;border-radius:4px;box-shadow:0 5px 5px -3px #0003,0 8px 10px 1px #00000024,0 3px 14px 2px #0000001f}.cdk-drag-placeholder{opacity:0}.cdk-drag-animating{transition:transform .25s cubic-bezier(0,0,.2,1)}.cards.cdk-drop-list-dragging .card:not(.cdk-drag-placeholder){transition:transform .25s cubic-bezier(0,0,.2,1)}\n"], dependencies: [{ kind: "directive", type: NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: NgStyle, selector: "[ngStyle]", inputs: ["ngStyle"] }, { kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "ngmodule", type: DragDropModule }, { kind: "directive", type: i1.CdkDropList, selector: "[cdkDropList], cdk-drop-list", inputs: ["cdkDropListConnectedTo", "cdkDropListData", "cdkDropListOrientation", "id", "cdkDropListLockAxis", "cdkDropListDisabled", "cdkDropListSortingDisabled", "cdkDropListEnterPredicate", "cdkDropListSortPredicate", "cdkDropListAutoScrollDisabled", "cdkDropListAutoScrollStep", "cdkDropListElementContainer", "cdkDropListHasAnchor"], outputs: ["cdkDropListDropped", "cdkDropListEntered", "cdkDropListExited", "cdkDropListSorted"], exportAs: ["cdkDropList"] }, { kind: "directive", type: i1.CdkDropListGroup, selector: "[cdkDropListGroup]", inputs: ["cdkDropListGroupDisabled"], exportAs: ["cdkDropListGroup"] }, { kind: "directive", type: i1.CdkDrag, selector: "[cdkDrag]", inputs: ["cdkDragData", "cdkDragLockAxis", "cdkDragRootElement", "cdkDragBoundary", "cdkDragStartDelay", "cdkDragFreeDragPosition", "cdkDragDisabled", "cdkDragConstrainPosition", "cdkDragPreviewClass", "cdkDragPreviewContainer", "cdkDragScale"], outputs: ["cdkDragStarted", "cdkDragReleased", "cdkDragEnded", "cdkDragEntered", "cdkDragExited", "cdkDragDropped", "cdkDragMoved"], exportAs: ["cdkDrag"] }] });
|
|
135
257
|
}
|
|
136
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "
|
|
258
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.2.3", ngImport: i0, type: HubBoardComponent, decorators: [{
|
|
137
259
|
type: Component,
|
|
138
260
|
args: [{ selector: 'hub-board, hub-ui-board', standalone: true, imports: [NgClass, NgStyle, NgTemplateOutlet, DragDropModule], template: "@if (columns().length) {\n\t<div\n\t\tclass=\"hub-board\"\n\t\tcdkDropList\n\t\tcdkDropListOrientation=\"horizontal\"\n\t\t[cdkDropListData]=\"columns()\"\n\t\t(cdkDropListDropped)=\"dropColumn($event)\"\n\t\t[cdkDropListSortingDisabled]=\"columnSortingDisabled()\"\n\t>\n\t\t<div cdkDropListGroup class=\"hub-board__columns\">\n\t\t\t@for (column of columns(); let index = $index; track column) {\n\t\t\t\t<div\n\t\t\t\t\tclass=\"hub-board__column-container\"\n\t\t\t\t\tcdkDrag\n\t\t\t\t\t[cdkDragData]=\"column\"\n\t\t\t\t\t[cdkDragDisabled]=\"column.disabled\"\n\t\t\t\t>\n\t\t\t\t\t<div\n\t\t\t\t\t\tclass=\"hub-board__column\"\n\t\t\t\t\t\t[ngClass]=\"column.classlist\"\n\t\t\t\t\t\t[ngStyle]=\"column.style\"\n\t\t\t\t\t>\n\t\t\t\t\t\t<div class=\"hub-board__column-header\">\n\t\t\t\t\t\t\t<ng-container\n\t\t\t\t\t\t\t\t[ngTemplateOutlet]=\"\n\t\t\t\t\t\t\t\t\tcolumnHeaderTpt() || defaultColumnHeaderTpt\n\t\t\t\t\t\t\t\t\"\n\t\t\t\t\t\t\t\t[ngTemplateOutletContext]=\"{ column: column }\"\n\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t</ng-container>\n\t\t\t\t\t\t</div>\n\t\t\t\t\t\t<div\n\t\t\t\t\t\t\tclass=\"hub-board__column-body\"\n\t\t\t\t\t\t\tcdkDropList\n\t\t\t\t\t\t\t[cdkDropListData]=\"column\"\n\t\t\t\t\t\t\t(cdkDropListDropped)=\"dropCard($event)\"\n\t\t\t\t\t\t\t(scroll)=\"onScroll(index, $event)\"\n\t\t\t\t\t\t\t[cdkDropListEnterPredicate]=\"\n\t\t\t\t\t\t\t\tcolumn.predicate ?? defaultEnterPredicateFn\n\t\t\t\t\t\t\t\"\n\t\t\t\t\t\t\t[cdkDropListSortingDisabled]=\"\n\t\t\t\t\t\t\t\tcolumn.cardSortingDisabled\n\t\t\t\t\t\t\t\"\n\t\t\t\t\t\t>\n\t\t\t\t\t\t\t@for (\n\t\t\t\t\t\t\t\tcard of column.cards;\n\t\t\t\t\t\t\t\tlet index = $index;\n\t\t\t\t\t\t\t\ttrack card\n\t\t\t\t\t\t\t) {\n\t\t\t\t\t\t\t\t<div\n\t\t\t\t\t\t\t\t\tclass=\"hub-board__card\"\n\t\t\t\t\t\t\t\t\t[class.hub-board__card--disabled]=\"\n\t\t\t\t\t\t\t\t\t\tcard.disabled\n\t\t\t\t\t\t\t\t\t\"\n\t\t\t\t\t\t\t\t\tcdkDrag\n\t\t\t\t\t\t\t\t\t[cdkDragData]=\"card\"\n\t\t\t\t\t\t\t\t\t[cdkDragDisabled]=\"card.disabled\"\n\t\t\t\t\t\t\t\t\t(click)=\"cardClick(card)\"\n\t\t\t\t\t\t\t\t\t(mousedown)=\"\n\t\t\t\t\t\t\t\t\t\tcard.disabled &&\n\t\t\t\t\t\t\t\t\t\t\t$event.stopPropagation()\n\t\t\t\t\t\t\t\t\t\"\n\t\t\t\t\t\t\t\t\t[ngClass]=\"card.classlist\"\n\t\t\t\t\t\t\t\t\t[ngStyle]=\"card.style\"\n\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t<div class=\"hub-board__card-body\">\n\t\t\t\t\t\t\t\t\t\t<ng-container\n\t\t\t\t\t\t\t\t\t\t\t[ngTemplateOutlet]=\"\n\t\t\t\t\t\t\t\t\t\t\t\tcardTpt() || defaultCardTpt\n\t\t\t\t\t\t\t\t\t\t\t\"\n\t\t\t\t\t\t\t\t\t\t\t[ngTemplateOutletContext]=\"{\n\t\t\t\t\t\t\t\t\t\t\t\titem: card,\n\t\t\t\t\t\t\t\t\t\t\t\tcolumn\n\t\t\t\t\t\t\t\t\t\t\t}\"\n\t\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t</ng-container>\n\t\t\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t</div>\n\n\t\t\t\t\t\t@if (columnFooterTpt()) {\n\t\t\t\t\t\t\t<div class=\"hub-board__column-footer\">\n\t\t\t\t\t\t\t\t<ng-container\n\t\t\t\t\t\t\t\t\t[ngTemplateOutlet]=\"\n\t\t\t\t\t\t\t\t\t\tcolumnFooterTpt() ?? null\n\t\t\t\t\t\t\t\t\t\"\n\t\t\t\t\t\t\t\t\t[ngTemplateOutletContext]=\"{\n\t\t\t\t\t\t\t\t\t\tcolumn: column\n\t\t\t\t\t\t\t\t\t}\"\n\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t</ng-container>\n\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t}\n\t\t\t\t\t</div>\n\t\t\t\t</div>\n\t\t\t}\n\t\t</div>\n\t</div>\n}\n\n<ng-template #defaultCardTpt let-item=\"item\">\n\t<h6>{{ item.title }}</h6>\n\t<p class=\"card-text\">{{ item.description }}</p>\n</ng-template>\n\n<ng-template #defaultColumnHeaderTpt let-column=\"column\">\n\t<div class=\"d-flex flex-column\">\n\t\t<h5 class=\"hub-board__column-header-title\">\n\t\t\t{{ column.title }}\n\t\t</h5>\n\t\t<h6 class=\"hub-board__column-header-subtitle\">\n\t\t\t{{ column.description }}\n\t\t</h6>\n\t</div>\n</ng-template>\n", styles: [":host{display:block;overflow:auto;width:100%;height:100%}.hub-board__column-body{min-height:128px}.cdk-drag-preview{box-sizing:border-box;border-radius:4px;box-shadow:0 5px 5px -3px #0003,0 8px 10px 1px #00000024,0 3px 14px 2px #0000001f}.cdk-drag-placeholder{opacity:0}.cdk-drag-animating{transition:transform .25s cubic-bezier(0,0,.2,1)}.cards.cdk-drop-list-dragging .card:not(.cdk-drag-placeholder){transition:transform .25s cubic-bezier(0,0,.2,1)}\n"] }]
|
|
139
|
-
}]
|
|
140
|
-
type: Output
|
|
141
|
-
}], onCardMoved: [{
|
|
142
|
-
type: Output
|
|
143
|
-
}], onColumnMoved: [{
|
|
144
|
-
type: Output
|
|
145
|
-
}], reachedEnd: [{
|
|
146
|
-
type: Output
|
|
147
|
-
}] } });
|
|
261
|
+
}] });
|
|
148
262
|
|
|
263
|
+
/**
|
|
264
|
+
* Angular module that provides board functionality with drag-and-drop support.
|
|
265
|
+
*
|
|
266
|
+
* This module includes all the necessary components and directives for creating
|
|
267
|
+
* Kanban-style boards with customizable columns, cards, and templates.
|
|
268
|
+
*
|
|
269
|
+
* @deprecated Use standalone components instead. Import individual components and directives directly.
|
|
270
|
+
* @publicApi
|
|
271
|
+
*
|
|
272
|
+
* @example
|
|
273
|
+
* ```typescript
|
|
274
|
+
* // Legacy module approach (not recommended)
|
|
275
|
+
* import { BoardModule } from 'ng-hub-ui-board';
|
|
276
|
+
*
|
|
277
|
+
* @NgModule({
|
|
278
|
+
* imports: [BoardModule]
|
|
279
|
+
* })
|
|
280
|
+
* export class AppModule {}
|
|
281
|
+
*
|
|
282
|
+
* // Recommended standalone approach
|
|
283
|
+
* import { HubBoardComponent, CardTemplateDirective } from 'ng-hub-ui-board';
|
|
284
|
+
*
|
|
285
|
+
* @Component({
|
|
286
|
+
* standalone: true,
|
|
287
|
+
* imports: [HubBoardComponent, CardTemplateDirective]
|
|
288
|
+
* })
|
|
289
|
+
* export class MyComponent {}
|
|
290
|
+
* ```
|
|
291
|
+
*/
|
|
149
292
|
class BoardModule {
|
|
150
|
-
static
|
|
151
|
-
static
|
|
293
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.2.3", ngImport: i0, type: BoardModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule });
|
|
294
|
+
static ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "20.2.3", ngImport: i0, type: BoardModule, imports: [HubBoardComponent,
|
|
152
295
|
CardTemplateDirective,
|
|
153
296
|
BoardColumnHeaderDirective,
|
|
154
297
|
BoardColumnFooterDirective], exports: [HubBoardComponent,
|
|
155
298
|
CardTemplateDirective,
|
|
156
299
|
BoardColumnHeaderDirective,
|
|
157
|
-
BoardColumnFooterDirective] });
|
|
158
|
-
static
|
|
300
|
+
BoardColumnFooterDirective] });
|
|
301
|
+
static ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "20.2.3", ngImport: i0, type: BoardModule, imports: [HubBoardComponent] });
|
|
159
302
|
}
|
|
160
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "
|
|
303
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.2.3", ngImport: i0, type: BoardModule, decorators: [{
|
|
161
304
|
type: NgModule,
|
|
162
305
|
args: [{
|
|
163
306
|
declarations: [],
|
|
@@ -176,39 +319,58 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.8", ngImpor
|
|
|
176
319
|
}]
|
|
177
320
|
}] });
|
|
178
321
|
|
|
322
|
+
/**
|
|
323
|
+
* Converts a hexadecimal color string into its inverted counterpart, offering both
|
|
324
|
+
* high-contrast black/white and full-spectrum inversion modes.
|
|
325
|
+
*
|
|
326
|
+
* @publicApi
|
|
327
|
+
*/
|
|
179
328
|
class InvertColorPipe {
|
|
329
|
+
/**
|
|
330
|
+
* Inverts a HEX color value.
|
|
331
|
+
*
|
|
332
|
+
* @param hex - Color expressed as a 3- or 6-digit HEX string with or without a hash prefix.
|
|
333
|
+
* @param bw - When `true`, returns either black or white based on perceived brightness to maximise contrast.
|
|
334
|
+
* @returns The inverted color represented as a 6-digit HEX string (always prefixed with `#`).
|
|
335
|
+
* @throws Error if the provided value cannot be parsed as a valid HEX color.
|
|
336
|
+
*/
|
|
180
337
|
transform(hex, bw) {
|
|
181
338
|
if (!hex) {
|
|
182
339
|
return '#000000';
|
|
183
340
|
}
|
|
184
|
-
|
|
185
|
-
|
|
341
|
+
let normalizedHex = hex;
|
|
342
|
+
if (normalizedHex.indexOf('#') === 0) {
|
|
343
|
+
normalizedHex = normalizedHex.slice(1);
|
|
186
344
|
}
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
345
|
+
if (normalizedHex.length === 3) {
|
|
346
|
+
// Convert shorthand notation (e.g., #abc) to full length (#aabbcc)
|
|
347
|
+
normalizedHex =
|
|
348
|
+
normalizedHex[0] +
|
|
349
|
+
normalizedHex[0] +
|
|
350
|
+
normalizedHex[1] +
|
|
351
|
+
normalizedHex[1] +
|
|
352
|
+
normalizedHex[2] +
|
|
353
|
+
normalizedHex[2];
|
|
190
354
|
}
|
|
191
|
-
if (
|
|
355
|
+
if (normalizedHex.length !== 6) {
|
|
192
356
|
throw new Error('Invalid HEX color.');
|
|
193
357
|
}
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
358
|
+
const r = parseInt(normalizedHex.slice(0, 2), 16);
|
|
359
|
+
const g = parseInt(normalizedHex.slice(2, 4), 16);
|
|
360
|
+
const b = parseInt(normalizedHex.slice(4, 6), 16);
|
|
197
361
|
if (bw) {
|
|
198
362
|
// http://stackoverflow.com/a/3943023/112731
|
|
199
363
|
return r * 0.299 + g * 0.587 + b * 0.114 > 186 ? '#000000' : '#FFFFFF';
|
|
200
364
|
}
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
// pad each with zeros and return
|
|
206
|
-
return '#' + r.padStart(2, 0) + g.padStart(2, 0) + b.padStart(2, 0);
|
|
365
|
+
const invertedR = (255 - r).toString(16).padStart(2, '0');
|
|
366
|
+
const invertedG = (255 - g).toString(16).padStart(2, '0');
|
|
367
|
+
const invertedB = (255 - b).toString(16).padStart(2, '0');
|
|
368
|
+
return `#${invertedR}${invertedG}${invertedB}`;
|
|
207
369
|
}
|
|
208
|
-
static
|
|
209
|
-
static
|
|
370
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.2.3", ngImport: i0, type: InvertColorPipe, deps: [], target: i0.ɵɵFactoryTarget.Pipe });
|
|
371
|
+
static ɵpipe = i0.ɵɵngDeclarePipe({ minVersion: "14.0.0", version: "20.2.3", ngImport: i0, type: InvertColorPipe, isStandalone: true, name: "invertColor" });
|
|
210
372
|
}
|
|
211
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "
|
|
373
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.2.3", ngImport: i0, type: InvertColorPipe, decorators: [{
|
|
212
374
|
type: Pipe,
|
|
213
375
|
args: [{
|
|
214
376
|
name: 'invertColor',
|