@mk-kit/ui 0.52.1 → 0.53.0
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/fesm2022/mk-kit-ui-data.mjs +5 -417
- package/fesm2022/mk-kit-ui-data.mjs.map +1 -1
- package/fesm2022/mk-kit-ui-feedback.mjs +1 -1
- package/fesm2022/mk-kit-ui-feedback.mjs.map +1 -1
- package/fesm2022/mk-kit-ui-kanban.mjs +133 -0
- package/fesm2022/mk-kit-ui-kanban.mjs.map +1 -0
- package/fesm2022/mk-kit-ui-status.mjs +318 -0
- package/fesm2022/mk-kit-ui-status.mjs.map +1 -0
- package/fesm2022/mk-kit-ui-table.mjs +49 -1
- package/fesm2022/mk-kit-ui-table.mjs.map +1 -1
- package/fesm2022/mk-kit-ui.mjs +2 -0
- package/fesm2022/mk-kit-ui.mjs.map +1 -1
- package/package.json +9 -1
- package/types/mk-kit-ui-data.d.ts +3 -247
- package/types/mk-kit-ui-kanban.d.ts +98 -0
- package/types/mk-kit-ui-status.d.ts +158 -0
- package/types/mk-kit-ui-table.d.ts +26 -2
- package/types/mk-kit-ui.d.ts +2 -0
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
import { NgTemplateOutlet } from '@angular/common';
|
|
2
|
+
import * as i0 from '@angular/core';
|
|
3
|
+
import { model, input, booleanAttribute, output, contentChild, TemplateRef, computed, ChangeDetectionStrategy, Component } from '@angular/core';
|
|
4
|
+
import { mkUniqueId } from '@mk-kit/ui/core';
|
|
5
|
+
import { mkMoveItemInArray, MkDropList, MkDrag } from '@mk-kit/ui/dnd';
|
|
6
|
+
|
|
7
|
+
/** Stable empty fallback so out-of-range lookups don't allocate per call. */
|
|
8
|
+
const NO_CONNECTIONS = [];
|
|
9
|
+
/**
|
|
10
|
+
* Kanban board — a horizontal row of columns whose cards can be dragged and
|
|
11
|
+
* reordered within a column or transferred between columns. Built on the dnd
|
|
12
|
+
* group's connected `[mkDropList]` / `[mkDrag]` directives, so it inherits both
|
|
13
|
+
* pointer and keyboard dragging (WCAG 2.1.1) for free.
|
|
14
|
+
*
|
|
15
|
+
* Bind `columns` two-way; the model is updated immutably on each drop. Project
|
|
16
|
+
* an `<ng-template>` to render custom card content — it receives the card as
|
|
17
|
+
* `$implicit` and the owning column as `column`:
|
|
18
|
+
*
|
|
19
|
+
* ```html
|
|
20
|
+
* <mk-kanban [(columns)]="board" (cardMoved)="onMoved($event)">
|
|
21
|
+
* <ng-template #cardTemplate let-card let-column="column">
|
|
22
|
+
* <strong>{{ card.title }}</strong>
|
|
23
|
+
* </ng-template>
|
|
24
|
+
* </mk-kanban>
|
|
25
|
+
* ```
|
|
26
|
+
*/
|
|
27
|
+
class MkKanban {
|
|
28
|
+
/** The board's columns and their cards (two-way). Updated on every drop. */
|
|
29
|
+
columns = model([], /* @ts-ignore */
|
|
30
|
+
...(ngDevMode ? [{ debugName: "columns" }] : /* istanbul ignore next */ []));
|
|
31
|
+
/** Disable all dragging on the board. */
|
|
32
|
+
disabled = input(false, { ...(ngDevMode ? { debugName: "disabled" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
|
|
33
|
+
/** Emitted after the model is updated when a card is moved. */
|
|
34
|
+
cardMoved = output();
|
|
35
|
+
/** Optional consumer-projected card renderer (`$implicit` = card). */
|
|
36
|
+
cardTemplate = contentChild(TemplateRef, /* @ts-ignore */
|
|
37
|
+
...(ngDevMode ? [{ debugName: "cardTemplate" }] : /* istanbul ignore next */ []));
|
|
38
|
+
/** Board-scoped prefix so this board's drop-list ids never collide. */
|
|
39
|
+
boardId = mkUniqueId('mk-kanban');
|
|
40
|
+
/** Column count as its own computed so id arrays survive card-only updates. */
|
|
41
|
+
columnCount = computed(() => this.columns().length, /* @ts-ignore */
|
|
42
|
+
...(ngDevMode ? [{ debugName: "columnCount" }] : /* istanbul ignore next */ []));
|
|
43
|
+
/** Stable drop-list id per column, positionally matched to `columns()`. */
|
|
44
|
+
listIds = computed(() => Array.from({ length: this.columnCount() }, (_, i) => `${this.boardId}-col-${i}`), /* @ts-ignore */
|
|
45
|
+
...(ngDevMode ? [{ debugName: "listIds" }] : /* istanbul ignore next */ []));
|
|
46
|
+
/**
|
|
47
|
+
* Per-column connected-target ids (every other column's list). One stable
|
|
48
|
+
* array per column, recomputed only when the column count changes — a fresh
|
|
49
|
+
* array per change-detection pass would dirty each `MkDropList`'s
|
|
50
|
+
* `connectedTo` input identity on every cycle.
|
|
51
|
+
*/
|
|
52
|
+
connections = computed(() => {
|
|
53
|
+
const ids = this.listIds();
|
|
54
|
+
return ids.map((_, i) => ids.filter((_, j) => j !== i));
|
|
55
|
+
}, /* @ts-ignore */
|
|
56
|
+
...(ngDevMode ? [{ debugName: "connections" }] : /* istanbul ignore next */ []));
|
|
57
|
+
/** Ids of every other column's list — the connected transfer targets for `i`. */
|
|
58
|
+
connectedTo(index) {
|
|
59
|
+
return this.connections()[index] ?? NO_CONNECTIONS;
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* Apply a drop from the dnd module. Reads the source/target columns from the
|
|
63
|
+
* event's containers (matched by their drop-list ids), updates the two-way
|
|
64
|
+
* `columns` model immutably, then emits {@link cardMoved}.
|
|
65
|
+
*/
|
|
66
|
+
onDrop(event) {
|
|
67
|
+
const ids = this.listIds();
|
|
68
|
+
const fromCol = ids.indexOf(event.previousContainer.id());
|
|
69
|
+
const toCol = ids.indexOf(event.container.id());
|
|
70
|
+
if (fromCol === -1 || toCol === -1)
|
|
71
|
+
return;
|
|
72
|
+
this.moveCard(fromCol, toCol, event.previousIndex, event.currentIndex);
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* Immutably move the card at `fromIndex` of column `fromCol` to `toIndex` of
|
|
76
|
+
* column `toCol`, updating the model and emitting {@link cardMoved}. Column
|
|
77
|
+
* indices refer to positions in `columns()`.
|
|
78
|
+
*/
|
|
79
|
+
moveCard(fromCol, toCol, fromIndex, toIndex) {
|
|
80
|
+
const cols = this.columns();
|
|
81
|
+
const source = cols[fromCol];
|
|
82
|
+
const target = cols[toCol];
|
|
83
|
+
if (!source || !target)
|
|
84
|
+
return;
|
|
85
|
+
const card = source.cards[fromIndex];
|
|
86
|
+
if (!card)
|
|
87
|
+
return;
|
|
88
|
+
const next = cols.map((col, i) => {
|
|
89
|
+
if (fromCol === toCol && i === fromCol) {
|
|
90
|
+
const cards = [...col.cards];
|
|
91
|
+
mkMoveItemInArray(cards, fromIndex, toIndex);
|
|
92
|
+
return { ...col, cards };
|
|
93
|
+
}
|
|
94
|
+
if (i === fromCol) {
|
|
95
|
+
return { ...col, cards: col.cards.filter((_, idx) => idx !== fromIndex) };
|
|
96
|
+
}
|
|
97
|
+
if (i === toCol) {
|
|
98
|
+
const cards = [...col.cards];
|
|
99
|
+
cards.splice(Math.max(0, Math.min(toIndex, cards.length)), 0, card);
|
|
100
|
+
return { ...col, cards };
|
|
101
|
+
}
|
|
102
|
+
return col;
|
|
103
|
+
});
|
|
104
|
+
this.columns.set(next);
|
|
105
|
+
this.cardMoved.emit({
|
|
106
|
+
card,
|
|
107
|
+
from: source.id,
|
|
108
|
+
to: target.id,
|
|
109
|
+
fromIndex,
|
|
110
|
+
toIndex,
|
|
111
|
+
});
|
|
112
|
+
}
|
|
113
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.7", ngImport: i0, type: MkKanban, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
114
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.0.7", type: MkKanban, isStandalone: true, selector: "mk-kanban", inputs: { columns: { classPropertyName: "columns", publicName: "columns", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { columns: "columnsChange", cardMoved: "cardMoved" }, host: { classAttribute: "mk-kanban" }, queries: [{ propertyName: "cardTemplate", first: true, predicate: TemplateRef, descendants: true, isSignal: true }], ngImport: i0, template: "<div class=\"mk-kanban__board\">\n @for (column of columns(); track column.id; let colIndex = $index) {\n <section\n class=\"mk-kanban__column\"\n role=\"region\"\n [attr.aria-label]=\"column.title\"\n >\n <header class=\"mk-kanban__column-header\">\n <span class=\"mk-kanban__column-title\">{{ column.title }}</span>\n <span class=\"mk-kanban__column-count\" aria-hidden=\"true\">\n {{ column.cards.length }}\n </span>\n </header>\n\n <div\n mkDropList\n class=\"mk-kanban__cards\"\n [mkDropListData]=\"column.cards\"\n [mkDropListId]=\"listIds()[colIndex]\"\n [mkDropListLabel]=\"column.title\"\n [mkDropListConnectedTo]=\"connectedTo(colIndex)\"\n [mkDropListDisabled]=\"disabled()\"\n mkDropListOrientation=\"vertical\"\n (mkDropListDropped)=\"onDrop($event)\"\n >\n @for (card of column.cards; track card.id) {\n <div\n mkDrag\n class=\"mk-kanban__card\"\n [mkDragData]=\"card\"\n [mkDragDisabled]=\"disabled()\"\n >\n <ng-container\n [ngTemplateOutlet]=\"cardTemplate() ?? defaultCard\"\n [ngTemplateOutletContext]=\"{ $implicit: card, column: column }\"\n />\n </div>\n }\n </div>\n </section>\n }\n</div>\n\n<ng-template #defaultCard let-card>\n <span class=\"mk-kanban__card-title\">{{ card.title }}</span>\n</ng-template>\n", styles: [":host{display:block;color:var(--mk-text)}.mk-kanban__board{display:flex;gap:var(--mk-space-4);align-items:flex-start;overflow-x:auto;padding-bottom:var(--mk-space-2)}.mk-kanban__column{display:flex;flex-direction:column;flex:0 0 auto;width:17rem;max-height:100%;background-color:var(--mk-surface-2);border:var(--mk-border-width) solid var(--mk-border);border-radius:var(--mk-radius-lg)}.mk-kanban__column-header{display:flex;align-items:center;justify-content:space-between;gap:var(--mk-space-2);padding:var(--mk-space-3) var(--mk-space-4);font-weight:600;border-bottom:var(--mk-border-width) solid var(--mk-border)}.mk-kanban__column-title{min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.mk-kanban__column-count{flex:0 0 auto;min-width:1.5rem;padding:0 var(--mk-space-2);font-size:.75rem;font-weight:600;line-height:1.5rem;text-align:center;color:var(--mk-text-muted);background-color:var(--mk-surface);border-radius:var(--mk-radius-md)}.mk-kanban__cards{display:flex;flex-direction:column;gap:var(--mk-space-2);flex:1 1 auto;min-height:var(--mk-space-8);padding:var(--mk-space-3);overflow-y:auto}.mk-kanban__card{padding:var(--mk-space-3) var(--mk-space-4);background-color:var(--mk-surface);border:var(--mk-border-width) solid var(--mk-border);border-radius:var(--mk-radius-md);box-shadow:var(--mk-shadow-sm)}.mk-kanban__card:focus-visible{outline:var(--mk-focus-ring-width) solid var(--mk-focus-ring);outline-offset:var(--mk-focus-ring-offset)}.mk-kanban__card-title{display:block;min-width:0;overflow-wrap:anywhere}\n"], dependencies: [{ kind: "component", type: MkDropList, selector: "[mkDropList]", inputs: ["mkDropListData", "mkDropListId", "mkDropListConnectedTo", "mkDropListLabel", "mkDropListLabelledBy", "mkDropListOrientation", "mkDropListDisabled"], outputs: ["mkDropListDropped"], exportAs: ["mkDropList"] }, { kind: "component", type: MkDrag, selector: "[mkDrag]", inputs: ["mkDragData", "mkDragDisabled", "mkDragTouchDelay"], exportAs: ["mkDrag"] }, { kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
115
|
+
}
|
|
116
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.7", ngImport: i0, type: MkKanban, decorators: [{
|
|
117
|
+
type: Component,
|
|
118
|
+
args: [{ selector: 'mk-kanban', changeDetection: ChangeDetectionStrategy.OnPush, imports: [MkDropList, MkDrag, NgTemplateOutlet], host: { class: 'mk-kanban' }, template: "<div class=\"mk-kanban__board\">\n @for (column of columns(); track column.id; let colIndex = $index) {\n <section\n class=\"mk-kanban__column\"\n role=\"region\"\n [attr.aria-label]=\"column.title\"\n >\n <header class=\"mk-kanban__column-header\">\n <span class=\"mk-kanban__column-title\">{{ column.title }}</span>\n <span class=\"mk-kanban__column-count\" aria-hidden=\"true\">\n {{ column.cards.length }}\n </span>\n </header>\n\n <div\n mkDropList\n class=\"mk-kanban__cards\"\n [mkDropListData]=\"column.cards\"\n [mkDropListId]=\"listIds()[colIndex]\"\n [mkDropListLabel]=\"column.title\"\n [mkDropListConnectedTo]=\"connectedTo(colIndex)\"\n [mkDropListDisabled]=\"disabled()\"\n mkDropListOrientation=\"vertical\"\n (mkDropListDropped)=\"onDrop($event)\"\n >\n @for (card of column.cards; track card.id) {\n <div\n mkDrag\n class=\"mk-kanban__card\"\n [mkDragData]=\"card\"\n [mkDragDisabled]=\"disabled()\"\n >\n <ng-container\n [ngTemplateOutlet]=\"cardTemplate() ?? defaultCard\"\n [ngTemplateOutletContext]=\"{ $implicit: card, column: column }\"\n />\n </div>\n }\n </div>\n </section>\n }\n</div>\n\n<ng-template #defaultCard let-card>\n <span class=\"mk-kanban__card-title\">{{ card.title }}</span>\n</ng-template>\n", styles: [":host{display:block;color:var(--mk-text)}.mk-kanban__board{display:flex;gap:var(--mk-space-4);align-items:flex-start;overflow-x:auto;padding-bottom:var(--mk-space-2)}.mk-kanban__column{display:flex;flex-direction:column;flex:0 0 auto;width:17rem;max-height:100%;background-color:var(--mk-surface-2);border:var(--mk-border-width) solid var(--mk-border);border-radius:var(--mk-radius-lg)}.mk-kanban__column-header{display:flex;align-items:center;justify-content:space-between;gap:var(--mk-space-2);padding:var(--mk-space-3) var(--mk-space-4);font-weight:600;border-bottom:var(--mk-border-width) solid var(--mk-border)}.mk-kanban__column-title{min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.mk-kanban__column-count{flex:0 0 auto;min-width:1.5rem;padding:0 var(--mk-space-2);font-size:.75rem;font-weight:600;line-height:1.5rem;text-align:center;color:var(--mk-text-muted);background-color:var(--mk-surface);border-radius:var(--mk-radius-md)}.mk-kanban__cards{display:flex;flex-direction:column;gap:var(--mk-space-2);flex:1 1 auto;min-height:var(--mk-space-8);padding:var(--mk-space-3);overflow-y:auto}.mk-kanban__card{padding:var(--mk-space-3) var(--mk-space-4);background-color:var(--mk-surface);border:var(--mk-border-width) solid var(--mk-border);border-radius:var(--mk-radius-md);box-shadow:var(--mk-shadow-sm)}.mk-kanban__card:focus-visible{outline:var(--mk-focus-ring-width) solid var(--mk-focus-ring);outline-offset:var(--mk-focus-ring-offset)}.mk-kanban__card-title{display:block;min-width:0;overflow-wrap:anywhere}\n"] }]
|
|
119
|
+
}], propDecorators: { columns: [{ type: i0.Input, args: [{ isSignal: true, alias: "columns", required: false }] }, { type: i0.Output, args: ["columnsChange"] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }], cardMoved: [{ type: i0.Output, args: ["cardMoved"] }], cardTemplate: [{ type: i0.ContentChild, args: [i0.forwardRef(() => TemplateRef), { isSignal: true }] }] } });
|
|
120
|
+
|
|
121
|
+
/**
|
|
122
|
+
* @mk-kit/ui/kanban — the board (columns + drag-and-drop cards). Its own
|
|
123
|
+
* entry since 0.53 because it is the only `data` component that needs
|
|
124
|
+
* `@mk-kit/ui/dnd`; keeping it in `data` shipped dnd to every page that
|
|
125
|
+
* rendered a badge.
|
|
126
|
+
*/
|
|
127
|
+
|
|
128
|
+
/**
|
|
129
|
+
* Generated bundle index. Do not edit.
|
|
130
|
+
*/
|
|
131
|
+
|
|
132
|
+
export { MkKanban };
|
|
133
|
+
//# sourceMappingURL=mk-kit-ui-kanban.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mk-kit-ui-kanban.mjs","sources":["../../../projects/mk-kit/kanban/kanban.ts","../../../projects/mk-kit/kanban/kanban.html","../../../projects/mk-kit/kanban/index.ts","../../../projects/mk-kit/kanban/mk-kit-ui-kanban.ts"],"sourcesContent":["import { NgTemplateOutlet } from '@angular/common';\nimport {\n ChangeDetectionStrategy,\n Component,\n TemplateRef,\n booleanAttribute,\n computed,\n contentChild,\n input,\n model,\n output,\n} from '@angular/core';\nimport { mkUniqueId } from '@mk-kit/ui/core';\nimport { MkDrag, MkDropList, mkMoveItemInArray } from '@mk-kit/ui/dnd';\nimport type { MkDropEvent } from '@mk-kit/ui/dnd';\n\n/** Stable empty fallback so out-of-range lookups don't allocate per call. */\nconst NO_CONNECTIONS: string[] = [];\n\n/** A single draggable card on a {@link MkKanban} board. */\nexport interface MkKanbanCard {\n /** Stable identity used for tracking and move events. */\n id: unknown;\n /** Text shown by the default card renderer. */\n title: string;\n /** Arbitrary extra fields for custom card templates. */\n [key: string]: unknown;\n}\n\n/** A column (bucket) of {@link MkKanbanCard}s on a {@link MkKanban} board. */\nexport interface MkKanbanColumn {\n /** Stable identity used for tracking and move events. */\n id: unknown;\n /** Heading shown in the column header and used as its aria-label. */\n title: string;\n /** The ordered cards contained in this column. */\n cards: MkKanbanCard[];\n}\n\n/**\n * Emitted by {@link MkKanban} after a card has been moved (between or within\n * columns) and the two-way `columns` model has been updated.\n */\nexport interface MkKanbanCardMovedEvent {\n /** The card that was moved. */\n card: MkKanbanCard;\n /** `id` of the column the card came from. */\n from: unknown;\n /** `id` of the column the card was dropped into. */\n to: unknown;\n /** The card's index within the source column before the move. */\n fromIndex: number;\n /** The card's index within the destination column after the move. */\n toIndex: number;\n}\n\n/**\n * Kanban board — a horizontal row of columns whose cards can be dragged and\n * reordered within a column or transferred between columns. Built on the dnd\n * group's connected `[mkDropList]` / `[mkDrag]` directives, so it inherits both\n * pointer and keyboard dragging (WCAG 2.1.1) for free.\n *\n * Bind `columns` two-way; the model is updated immutably on each drop. Project\n * an `<ng-template>` to render custom card content — it receives the card as\n * `$implicit` and the owning column as `column`:\n *\n * ```html\n * <mk-kanban [(columns)]=\"board\" (cardMoved)=\"onMoved($event)\">\n * <ng-template #cardTemplate let-card let-column=\"column\">\n * <strong>{{ card.title }}</strong>\n * </ng-template>\n * </mk-kanban>\n * ```\n */\n@Component({\n selector: 'mk-kanban',\n templateUrl: './kanban.html',\n styleUrl: './kanban.scss',\n changeDetection: ChangeDetectionStrategy.OnPush,\n imports: [MkDropList, MkDrag, NgTemplateOutlet],\n host: { class: 'mk-kanban' },\n})\nexport class MkKanban {\n /** The board's columns and their cards (two-way). Updated on every drop. */\n readonly columns = model<MkKanbanColumn[]>([]);\n\n /** Disable all dragging on the board. */\n readonly disabled = input(false, { transform: booleanAttribute });\n\n /** Emitted after the model is updated when a card is moved. */\n readonly cardMoved = output<MkKanbanCardMovedEvent>();\n\n /** Optional consumer-projected card renderer (`$implicit` = card). */\n protected readonly cardTemplate = contentChild<TemplateRef<unknown>>(TemplateRef);\n\n /** Board-scoped prefix so this board's drop-list ids never collide. */\n private readonly boardId = mkUniqueId('mk-kanban');\n\n /** Column count as its own computed so id arrays survive card-only updates. */\n private readonly columnCount = computed(() => this.columns().length);\n\n /** Stable drop-list id per column, positionally matched to `columns()`. */\n protected readonly listIds = computed(() =>\n Array.from({ length: this.columnCount() }, (_, i) => `${this.boardId}-col-${i}`),\n );\n\n /**\n * Per-column connected-target ids (every other column's list). One stable\n * array per column, recomputed only when the column count changes — a fresh\n * array per change-detection pass would dirty each `MkDropList`'s\n * `connectedTo` input identity on every cycle.\n */\n private readonly connections = computed(() => {\n const ids = this.listIds();\n return ids.map((_, i) => ids.filter((_, j) => j !== i));\n });\n\n /** Ids of every other column's list — the connected transfer targets for `i`. */\n protected connectedTo(index: number): string[] {\n return this.connections()[index] ?? NO_CONNECTIONS;\n }\n\n /**\n * Apply a drop from the dnd module. Reads the source/target columns from the\n * event's containers (matched by their drop-list ids), updates the two-way\n * `columns` model immutably, then emits {@link cardMoved}.\n */\n protected onDrop(event: MkDropEvent<MkKanbanCard>): void {\n const ids = this.listIds();\n const fromCol = ids.indexOf(event.previousContainer.id());\n const toCol = ids.indexOf(event.container.id());\n if (fromCol === -1 || toCol === -1) return;\n this.moveCard(fromCol, toCol, event.previousIndex, event.currentIndex);\n }\n\n /**\n * Immutably move the card at `fromIndex` of column `fromCol` to `toIndex` of\n * column `toCol`, updating the model and emitting {@link cardMoved}. Column\n * indices refer to positions in `columns()`.\n */\n private moveCard(\n fromCol: number,\n toCol: number,\n fromIndex: number,\n toIndex: number,\n ): void {\n const cols = this.columns();\n const source = cols[fromCol];\n const target = cols[toCol];\n if (!source || !target) return;\n const card = source.cards[fromIndex];\n if (!card) return;\n\n const next = cols.map((col, i) => {\n if (fromCol === toCol && i === fromCol) {\n const cards = [...col.cards];\n mkMoveItemInArray(cards, fromIndex, toIndex);\n return { ...col, cards };\n }\n if (i === fromCol) {\n return { ...col, cards: col.cards.filter((_, idx) => idx !== fromIndex) };\n }\n if (i === toCol) {\n const cards = [...col.cards];\n cards.splice(Math.max(0, Math.min(toIndex, cards.length)), 0, card);\n return { ...col, cards };\n }\n return col;\n });\n\n this.columns.set(next);\n this.cardMoved.emit({\n card,\n from: source.id,\n to: target.id,\n fromIndex,\n toIndex,\n });\n }\n}\n","<div class=\"mk-kanban__board\">\n @for (column of columns(); track column.id; let colIndex = $index) {\n <section\n class=\"mk-kanban__column\"\n role=\"region\"\n [attr.aria-label]=\"column.title\"\n >\n <header class=\"mk-kanban__column-header\">\n <span class=\"mk-kanban__column-title\">{{ column.title }}</span>\n <span class=\"mk-kanban__column-count\" aria-hidden=\"true\">\n {{ column.cards.length }}\n </span>\n </header>\n\n <div\n mkDropList\n class=\"mk-kanban__cards\"\n [mkDropListData]=\"column.cards\"\n [mkDropListId]=\"listIds()[colIndex]\"\n [mkDropListLabel]=\"column.title\"\n [mkDropListConnectedTo]=\"connectedTo(colIndex)\"\n [mkDropListDisabled]=\"disabled()\"\n mkDropListOrientation=\"vertical\"\n (mkDropListDropped)=\"onDrop($event)\"\n >\n @for (card of column.cards; track card.id) {\n <div\n mkDrag\n class=\"mk-kanban__card\"\n [mkDragData]=\"card\"\n [mkDragDisabled]=\"disabled()\"\n >\n <ng-container\n [ngTemplateOutlet]=\"cardTemplate() ?? defaultCard\"\n [ngTemplateOutletContext]=\"{ $implicit: card, column: column }\"\n />\n </div>\n }\n </div>\n </section>\n }\n</div>\n\n<ng-template #defaultCard let-card>\n <span class=\"mk-kanban__card-title\">{{ card.title }}</span>\n</ng-template>\n","/**\n * @mk-kit/ui/kanban — the board (columns + drag-and-drop cards). Its own\n * entry since 0.53 because it is the only `data` component that needs\n * `@mk-kit/ui/dnd`; keeping it in `data` shipped dnd to every page that\n * rendered a badge.\n */\nexport * from './kanban';\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './index';\n"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,318 @@
|
|
|
1
|
+
import * as i0 from '@angular/core';
|
|
2
|
+
import { inject, input, ChangeDetectionStrategy, Component, booleanAttribute, ElementRef, Renderer2, DOCUMENT, PLATFORM_ID, numberAttribute, computed, effect, Directive } from '@angular/core';
|
|
3
|
+
import { MK_I18N, mkUniqueId } from '@mk-kit/ui/core';
|
|
4
|
+
import { isPlatformBrowser } from '@angular/common';
|
|
5
|
+
import { MkIcon } from '@mk-kit/ui/icon';
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Spinner — a circular indeterminate loading indicator. Exposes `role="status"`
|
|
9
|
+
* with a visually-hidden label so assistive tech announces the loading state.
|
|
10
|
+
* The animation slows under `prefers-reduced-motion`.
|
|
11
|
+
*
|
|
12
|
+
* ```html
|
|
13
|
+
* <mk-spinner />
|
|
14
|
+
* <mk-spinner size="lg" tone="neutral" label="Fetching results" />
|
|
15
|
+
* ```
|
|
16
|
+
*/
|
|
17
|
+
class MkSpinner {
|
|
18
|
+
i18n = inject(MK_I18N);
|
|
19
|
+
/** Size scale. */
|
|
20
|
+
size = input('md', /* @ts-ignore */
|
|
21
|
+
...(ngDevMode ? [{ debugName: "size" }] : /* istanbul ignore next */ []));
|
|
22
|
+
/** Semantic color tone. */
|
|
23
|
+
tone = input('primary', /* @ts-ignore */
|
|
24
|
+
...(ngDevMode ? [{ debugName: "tone" }] : /* istanbul ignore next */ []));
|
|
25
|
+
/** Visually-hidden status label announced to screen readers. */
|
|
26
|
+
label = input(this.i18n.loading, /* @ts-ignore */
|
|
27
|
+
...(ngDevMode ? [{ debugName: "label" }] : /* istanbul ignore next */ []));
|
|
28
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.7", ngImport: i0, type: MkSpinner, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
29
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "22.0.7", type: MkSpinner, isStandalone: true, selector: "mk-spinner", inputs: { size: { classPropertyName: "size", publicName: "size", isSignal: true, isRequired: false, transformFunction: null }, tone: { classPropertyName: "tone", publicName: "tone", isSignal: true, isRequired: false, transformFunction: null }, label: { classPropertyName: "label", publicName: "label", isSignal: true, isRequired: false, transformFunction: null } }, host: { attributes: { "role": "status" }, properties: { "class.mk-spinner--sm": "size() === 'sm'", "class.mk-spinner--md": "size() === 'md'", "class.mk-spinner--lg": "size() === 'lg'", "attr.data-tone": "tone()" }, classAttribute: "mk-spinner" }, ngImport: i0, template: "<span class=\"mk-spinner__circle\" aria-hidden=\"true\"></span>\n<span class=\"mk-spinner__sr\">{{ label() }}</span>\n", styles: [":host{--_color: var(--mk-primary);--_size: var(--mk-spinner-size, 1.5rem);--_thickness: var(--mk-spinner-thickness, 2px);display:inline-flex;align-items:center;justify-content:center;vertical-align:middle;color:var(--_color)}:host([data-tone=primary]){--_color: var(--mk-primary)}:host([data-tone=neutral]){--_color: var(--mk-text-muted)}:host([data-tone=success]){--_color: var(--mk-success)}:host([data-tone=warning]){--_color: var(--mk-warning)}:host([data-tone=danger]){--_color: var(--mk-danger)}:host([data-tone=info]){--_color: var(--mk-info)}:host(.mk-spinner--sm){--_size: var(--mk-spinner-size, 1rem);--_thickness: var(--mk-spinner-thickness, 2px)}:host(.mk-spinner--md){--_size: var(--mk-spinner-size, 1.5rem);--_thickness: var(--mk-spinner-thickness, 2px)}:host(.mk-spinner--lg){--_size: var(--mk-spinner-size, 2.25rem);--_thickness: var(--mk-spinner-thickness, 3px)}.mk-spinner__circle{display:block;width:var(--_size);height:var(--_size);border:var(--_thickness) solid currentColor;border-right-color:transparent;border-radius:50%;opacity:.9;animation:mk-spinner-spin .7s linear infinite}@keyframes mk-spinner-spin{to{transform:rotate(360deg)}}@media(prefers-reduced-motion:reduce){.mk-spinner__circle{animation-duration:1.6s}}.mk-spinner__sr{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0 0 0 0);white-space:nowrap;border:0}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
30
|
+
}
|
|
31
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.7", ngImport: i0, type: MkSpinner, decorators: [{
|
|
32
|
+
type: Component,
|
|
33
|
+
args: [{ selector: 'mk-spinner', changeDetection: ChangeDetectionStrategy.OnPush, host: {
|
|
34
|
+
class: 'mk-spinner',
|
|
35
|
+
role: 'status',
|
|
36
|
+
'[class.mk-spinner--sm]': "size() === 'sm'",
|
|
37
|
+
'[class.mk-spinner--md]': "size() === 'md'",
|
|
38
|
+
'[class.mk-spinner--lg]': "size() === 'lg'",
|
|
39
|
+
'[attr.data-tone]': 'tone()',
|
|
40
|
+
}, template: "<span class=\"mk-spinner__circle\" aria-hidden=\"true\"></span>\n<span class=\"mk-spinner__sr\">{{ label() }}</span>\n", styles: [":host{--_color: var(--mk-primary);--_size: var(--mk-spinner-size, 1.5rem);--_thickness: var(--mk-spinner-thickness, 2px);display:inline-flex;align-items:center;justify-content:center;vertical-align:middle;color:var(--_color)}:host([data-tone=primary]){--_color: var(--mk-primary)}:host([data-tone=neutral]){--_color: var(--mk-text-muted)}:host([data-tone=success]){--_color: var(--mk-success)}:host([data-tone=warning]){--_color: var(--mk-warning)}:host([data-tone=danger]){--_color: var(--mk-danger)}:host([data-tone=info]){--_color: var(--mk-info)}:host(.mk-spinner--sm){--_size: var(--mk-spinner-size, 1rem);--_thickness: var(--mk-spinner-thickness, 2px)}:host(.mk-spinner--md){--_size: var(--mk-spinner-size, 1.5rem);--_thickness: var(--mk-spinner-thickness, 2px)}:host(.mk-spinner--lg){--_size: var(--mk-spinner-size, 2.25rem);--_thickness: var(--mk-spinner-thickness, 3px)}.mk-spinner__circle{display:block;width:var(--_size);height:var(--_size);border:var(--_thickness) solid currentColor;border-right-color:transparent;border-radius:50%;opacity:.9;animation:mk-spinner-spin .7s linear infinite}@keyframes mk-spinner-spin{to{transform:rotate(360deg)}}@media(prefers-reduced-motion:reduce){.mk-spinner__circle{animation-duration:1.6s}}.mk-spinner__sr{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0 0 0 0);white-space:nowrap;border:0}\n"] }]
|
|
41
|
+
}], propDecorators: { size: [{ type: i0.Input, args: [{ isSignal: true, alias: "size", required: false }] }], tone: [{ type: i0.Input, args: [{ isSignal: true, alias: "tone", required: false }] }], label: [{ type: i0.Input, args: [{ isSignal: true, alias: "label", required: false }] }] } });
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* Badge — a compact status pill, typically for counts or short state labels.
|
|
45
|
+
* Set `dot` for a minimal notification indicator with no text.
|
|
46
|
+
*
|
|
47
|
+
* ```html
|
|
48
|
+
* <mk-badge tone="success">Active</mk-badge>
|
|
49
|
+
* <mk-badge tone="danger" variant="solid">3</mk-badge>
|
|
50
|
+
* <mk-badge tone="danger" dot aria-label="Unread messages" />
|
|
51
|
+
* ```
|
|
52
|
+
*/
|
|
53
|
+
class MkBadge {
|
|
54
|
+
/** Semantic color tone. */
|
|
55
|
+
tone = input('primary', /* @ts-ignore */
|
|
56
|
+
...(ngDevMode ? [{ debugName: "tone" }] : /* istanbul ignore next */ []));
|
|
57
|
+
/** Visual treatment. */
|
|
58
|
+
variant = input('soft', /* @ts-ignore */
|
|
59
|
+
...(ngDevMode ? [{ debugName: "variant" }] : /* istanbul ignore next */ []));
|
|
60
|
+
/** Size scale. */
|
|
61
|
+
size = input('md', /* @ts-ignore */
|
|
62
|
+
...(ngDevMode ? [{ debugName: "size" }] : /* istanbul ignore next */ []));
|
|
63
|
+
/** Render as a tiny dot (no text) for notification indicators. */
|
|
64
|
+
dot = input(false, { ...(ngDevMode ? { debugName: "dot" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
|
|
65
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.7", ngImport: i0, type: MkBadge, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
66
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.0.7", type: MkBadge, isStandalone: true, selector: "mk-badge", inputs: { tone: { classPropertyName: "tone", publicName: "tone", isSignal: true, isRequired: false, transformFunction: null }, variant: { classPropertyName: "variant", publicName: "variant", isSignal: true, isRequired: false, transformFunction: null }, size: { classPropertyName: "size", publicName: "size", isSignal: true, isRequired: false, transformFunction: null }, dot: { classPropertyName: "dot", publicName: "dot", isSignal: true, isRequired: false, transformFunction: null } }, host: { properties: { "class.mk-badge--sm": "size() === 'sm'", "class.mk-badge--md": "size() === 'md'", "class.mk-badge--lg": "size() === 'lg'", "class.mk-badge--solid": "variant() === 'solid'", "class.mk-badge--soft": "variant() === 'soft'", "class.mk-badge--outline": "variant() === 'outline'", "class.mk-badge--dot": "dot()", "attr.data-tone": "tone()" }, classAttribute: "mk-badge" }, ngImport: i0, template: "@if (!dot()) {\n <ng-content />\n}\n", styles: ["@charset \"UTF-8\";:host{--_main: var(--mk-primary);--_contrast: var(--mk-primary-contrast);--_subtle: var(--mk-primary-subtle);--_subtle-text: var(--mk-primary-subtle-text);display:inline-flex;align-items:center;justify-content:center;gap:var(--mk-space-1);height:1.375rem;min-width:1.375rem;padding:0 var(--mk-space-2);border:var(--mk-border-width) solid transparent;border-radius:var(--mk-radius-pill);font-family:inherit;font-size:var(--mk-font-size-xs);font-weight:var(--mk-font-weight-medium);line-height:1;white-space:nowrap;vertical-align:middle}:host([data-tone=primary]){--_main: var(--mk-primary);--_hover: var(--mk-primary-hover);--_active: var(--mk-primary-active);--_contrast: var(--mk-primary-contrast);--_subtle: var(--mk-primary-subtle);--_subtle-text: var(--mk-primary-subtle-text)}:host([data-tone=success]){--_main: var(--mk-success);--_hover: var(--mk-success-hover);--_active: var(--mk-success-hover);--_contrast: var(--mk-success-contrast);--_subtle: var(--mk-success-subtle);--_subtle-text: var(--mk-success-subtle-text)}:host([data-tone=warning]){--_main: var(--mk-warning);--_hover: var(--mk-warning-hover);--_active: var(--mk-warning-hover);--_contrast: var(--mk-warning-contrast);--_subtle: var(--mk-warning-subtle);--_subtle-text: var(--mk-warning-subtle-text)}:host([data-tone=danger]){--_main: var(--mk-danger);--_hover: var(--mk-danger-hover);--_active: var(--mk-danger-hover);--_contrast: var(--mk-danger-contrast);--_subtle: var(--mk-danger-subtle);--_subtle-text: var(--mk-danger-subtle-text)}:host([data-tone=info]){--_main: var(--mk-info);--_hover: var(--mk-info-hover);--_active: var(--mk-info-hover);--_contrast: var(--mk-info-contrast);--_subtle: var(--mk-info-subtle);--_subtle-text: var(--mk-info-subtle-text)}:host([data-tone=neutral]){--_main: var(--mk-surface-inverse);--_hover: var(--mk-surface-inverse);--_active: var(--mk-surface-inverse);--_contrast: var(--mk-text-inverse);--_subtle: var(--mk-neutral-subtle);--_subtle-text: var(--mk-neutral-subtle-text)}:host(.mk-badge--sm){height:1.125rem;min-width:1.125rem;padding:0 var(--mk-space-1);font-size:var(--mk-font-size-xs)}:host(.mk-badge--lg){height:1.625rem;min-width:1.625rem;padding:0 var(--mk-space-3);font-size:var(--mk-font-size-sm)}:host(.mk-badge--solid){background-color:var(--_main);color:var(--_contrast)}:host(.mk-badge--soft){background-color:var(--_subtle);color:var(--_subtle-text)}:host(.mk-badge--outline){background-color:transparent;color:var(--_subtle-text);border-color:color-mix(in srgb,var(--_main) 42%,var(--mk-border-strong))}:host(.mk-badge--dot){width:.625rem;height:.625rem;min-width:0;padding:0;border-radius:var(--mk-radius-circle)}:host(.mk-badge--dot.mk-badge--sm){width:.5rem;height:.5rem}:host(.mk-badge--dot.mk-badge--lg){width:.75rem;height:.75rem}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
67
|
+
}
|
|
68
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.7", ngImport: i0, type: MkBadge, decorators: [{
|
|
69
|
+
type: Component,
|
|
70
|
+
args: [{ selector: 'mk-badge', changeDetection: ChangeDetectionStrategy.OnPush, host: {
|
|
71
|
+
class: 'mk-badge',
|
|
72
|
+
'[class.mk-badge--sm]': "size() === 'sm'",
|
|
73
|
+
'[class.mk-badge--md]': "size() === 'md'",
|
|
74
|
+
'[class.mk-badge--lg]': "size() === 'lg'",
|
|
75
|
+
'[class.mk-badge--solid]': "variant() === 'solid'",
|
|
76
|
+
'[class.mk-badge--soft]': "variant() === 'soft'",
|
|
77
|
+
'[class.mk-badge--outline]': "variant() === 'outline'",
|
|
78
|
+
'[class.mk-badge--dot]': 'dot()',
|
|
79
|
+
'[attr.data-tone]': 'tone()',
|
|
80
|
+
}, template: "@if (!dot()) {\n <ng-content />\n}\n", styles: ["@charset \"UTF-8\";:host{--_main: var(--mk-primary);--_contrast: var(--mk-primary-contrast);--_subtle: var(--mk-primary-subtle);--_subtle-text: var(--mk-primary-subtle-text);display:inline-flex;align-items:center;justify-content:center;gap:var(--mk-space-1);height:1.375rem;min-width:1.375rem;padding:0 var(--mk-space-2);border:var(--mk-border-width) solid transparent;border-radius:var(--mk-radius-pill);font-family:inherit;font-size:var(--mk-font-size-xs);font-weight:var(--mk-font-weight-medium);line-height:1;white-space:nowrap;vertical-align:middle}:host([data-tone=primary]){--_main: var(--mk-primary);--_hover: var(--mk-primary-hover);--_active: var(--mk-primary-active);--_contrast: var(--mk-primary-contrast);--_subtle: var(--mk-primary-subtle);--_subtle-text: var(--mk-primary-subtle-text)}:host([data-tone=success]){--_main: var(--mk-success);--_hover: var(--mk-success-hover);--_active: var(--mk-success-hover);--_contrast: var(--mk-success-contrast);--_subtle: var(--mk-success-subtle);--_subtle-text: var(--mk-success-subtle-text)}:host([data-tone=warning]){--_main: var(--mk-warning);--_hover: var(--mk-warning-hover);--_active: var(--mk-warning-hover);--_contrast: var(--mk-warning-contrast);--_subtle: var(--mk-warning-subtle);--_subtle-text: var(--mk-warning-subtle-text)}:host([data-tone=danger]){--_main: var(--mk-danger);--_hover: var(--mk-danger-hover);--_active: var(--mk-danger-hover);--_contrast: var(--mk-danger-contrast);--_subtle: var(--mk-danger-subtle);--_subtle-text: var(--mk-danger-subtle-text)}:host([data-tone=info]){--_main: var(--mk-info);--_hover: var(--mk-info-hover);--_active: var(--mk-info-hover);--_contrast: var(--mk-info-contrast);--_subtle: var(--mk-info-subtle);--_subtle-text: var(--mk-info-subtle-text)}:host([data-tone=neutral]){--_main: var(--mk-surface-inverse);--_hover: var(--mk-surface-inverse);--_active: var(--mk-surface-inverse);--_contrast: var(--mk-text-inverse);--_subtle: var(--mk-neutral-subtle);--_subtle-text: var(--mk-neutral-subtle-text)}:host(.mk-badge--sm){height:1.125rem;min-width:1.125rem;padding:0 var(--mk-space-1);font-size:var(--mk-font-size-xs)}:host(.mk-badge--lg){height:1.625rem;min-width:1.625rem;padding:0 var(--mk-space-3);font-size:var(--mk-font-size-sm)}:host(.mk-badge--solid){background-color:var(--_main);color:var(--_contrast)}:host(.mk-badge--soft){background-color:var(--_subtle);color:var(--_subtle-text)}:host(.mk-badge--outline){background-color:transparent;color:var(--_subtle-text);border-color:color-mix(in srgb,var(--_main) 42%,var(--mk-border-strong))}:host(.mk-badge--dot){width:.625rem;height:.625rem;min-width:0;padding:0;border-radius:var(--mk-radius-circle)}:host(.mk-badge--dot.mk-badge--sm){width:.5rem;height:.5rem}:host(.mk-badge--dot.mk-badge--lg){width:.75rem;height:.75rem}\n"] }]
|
|
81
|
+
}], propDecorators: { tone: [{ type: i0.Input, args: [{ isSignal: true, alias: "tone", required: false }] }], variant: [{ type: i0.Input, args: [{ isSignal: true, alias: "variant", required: false }] }], size: [{ type: i0.Input, args: [{ isSignal: true, alias: "size", required: false }] }], dot: [{ type: i0.Input, args: [{ isSignal: true, alias: "dot", required: false }] }] } });
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* Badge overlay — anchors a small badge (count, dot or short text) to a corner
|
|
85
|
+
* of ANY element: an icon button, an avatar, a tab label. The host stays a
|
|
86
|
+
* single tab stop; the badge is a decorative, non-focusable child.
|
|
87
|
+
*
|
|
88
|
+
* - Numbers above `mkBadgeOverlayMax` (default 99) collapse to `99+`.
|
|
89
|
+
* - `mkBadgeOverlayDot` renders a textless dot ("something is new").
|
|
90
|
+
* - `mkBadgeOverlayAriaLabel` is the screen-reader text ("3 unread"). It is
|
|
91
|
+
* rendered in a visually hidden span and wired to the host with
|
|
92
|
+
* `aria-describedby`, so it is announced after the host's own name even
|
|
93
|
+
* when the host has an `aria-label`. When it is given, the visible badge is
|
|
94
|
+
* `aria-hidden` so the count is not read twice.
|
|
95
|
+
* - Positions use logical insets, so `top-end` sits at the top-right in LTR
|
|
96
|
+
* and the top-left in RTL.
|
|
97
|
+
*
|
|
98
|
+
* The badge is painted with the global `.mk-badge-overlay` styles from
|
|
99
|
+
* `@mk-kit/ui/styles.css` and follows the `--mk-*` tone tokens.
|
|
100
|
+
*
|
|
101
|
+
* ```html
|
|
102
|
+
* <button mkButton iconOnly aria-label="Notifications"
|
|
103
|
+
* [mkBadgeOverlay]="unread()" mkBadgeOverlayTone="danger"
|
|
104
|
+
* [mkBadgeOverlayAriaLabel]="unread() + ' unread'">
|
|
105
|
+
* <mk-icon name="bell" />
|
|
106
|
+
* </button>
|
|
107
|
+
*
|
|
108
|
+
* <mk-avatar name="Ada Lovelace" mkBadgeOverlay mkBadgeOverlayDot
|
|
109
|
+
* mkBadgeOverlayTone="success" mkBadgeOverlayPosition="bottom-end" />
|
|
110
|
+
* ```
|
|
111
|
+
*/
|
|
112
|
+
class MkBadgeOverlay {
|
|
113
|
+
host = inject(ElementRef);
|
|
114
|
+
renderer = inject(Renderer2);
|
|
115
|
+
document = inject(DOCUMENT);
|
|
116
|
+
isBrowser = isPlatformBrowser(inject(PLATFORM_ID));
|
|
117
|
+
/**
|
|
118
|
+
* Badge content — a count or a short label. `null` / empty hides the badge
|
|
119
|
+
* unless `mkBadgeOverlayDot` is set. Numeric strings are treated as numbers
|
|
120
|
+
* so `mkBadgeOverlay="120"` also collapses to `99+`.
|
|
121
|
+
*/
|
|
122
|
+
content = input(null, { ...(ngDevMode ? { debugName: "content" } : /* istanbul ignore next */ {}), alias: 'mkBadgeOverlay' });
|
|
123
|
+
/** Corner the badge is anchored to (logical: `end` flips in RTL). */
|
|
124
|
+
position = input('top-end', { ...(ngDevMode ? { debugName: "position" } : /* istanbul ignore next */ {}), alias: 'mkBadgeOverlayPosition' });
|
|
125
|
+
/** Semantic color tone (same scale as `mk-badge`). */
|
|
126
|
+
tone = input('primary', { ...(ngDevMode ? { debugName: "tone" } : /* istanbul ignore next */ {}), alias: 'mkBadgeOverlayTone' });
|
|
127
|
+
/** Render a textless dot instead of the content. */
|
|
128
|
+
dot = input(false, { ...(ngDevMode ? { debugName: "dot" } : /* istanbul ignore next */ {}), alias: 'mkBadgeOverlayDot',
|
|
129
|
+
transform: booleanAttribute });
|
|
130
|
+
/** Numbers above this render as `<max>+`. `0` disables the cap. */
|
|
131
|
+
max = input(99, { ...(ngDevMode ? { debugName: "max" } : /* istanbul ignore next */ {}), alias: 'mkBadgeOverlayMax',
|
|
132
|
+
transform: numberAttribute });
|
|
133
|
+
/** Hide the badge while keeping the directive (and its aria wiring) in place. */
|
|
134
|
+
hidden = input(false, { ...(ngDevMode ? { debugName: "hidden" } : /* istanbul ignore next */ {}), alias: 'mkBadgeOverlayHidden',
|
|
135
|
+
transform: booleanAttribute });
|
|
136
|
+
/**
|
|
137
|
+
* Screen-reader text for the badge, e.g. `"3 unread"`. Announced as the
|
|
138
|
+
* host's description; the visible badge becomes `aria-hidden`.
|
|
139
|
+
*/
|
|
140
|
+
ariaLabel = input('', { ...(ngDevMode ? { debugName: "ariaLabel" } : /* istanbul ignore next */ {}), alias: 'mkBadgeOverlayAriaLabel' });
|
|
141
|
+
/** The text painted in the badge (`''` in dot mode). */
|
|
142
|
+
label = computed(() => {
|
|
143
|
+
if (this.dot())
|
|
144
|
+
return '';
|
|
145
|
+
const raw = this.content();
|
|
146
|
+
if (raw === null || raw === undefined || raw === '')
|
|
147
|
+
return '';
|
|
148
|
+
const max = this.max();
|
|
149
|
+
const n = typeof raw === 'number' ? raw : /^\d+$/.test(raw) ? Number(raw) : NaN;
|
|
150
|
+
if (Number.isFinite(n) && max > 0 && n > max)
|
|
151
|
+
return `${max}+`;
|
|
152
|
+
return String(raw);
|
|
153
|
+
}, /* @ts-ignore */
|
|
154
|
+
...(ngDevMode ? [{ debugName: "label" }] : /* istanbul ignore next */ []));
|
|
155
|
+
/** Whether the badge is currently rendered. */
|
|
156
|
+
visible = computed(() => !this.hidden() && (this.dot() || this.label() !== ''), /* @ts-ignore */
|
|
157
|
+
...(ngDevMode ? [{ debugName: "visible" }] : /* istanbul ignore next */ []));
|
|
158
|
+
srId = mkUniqueId('mk-badge-overlay');
|
|
159
|
+
badge = null;
|
|
160
|
+
sr = null;
|
|
161
|
+
/** Set when WE made the host positioned, so we can undo it on removal. */
|
|
162
|
+
positionedHost = false;
|
|
163
|
+
constructor() {
|
|
164
|
+
if (!this.isBrowser)
|
|
165
|
+
return;
|
|
166
|
+
effect(() => {
|
|
167
|
+
const visible = this.visible();
|
|
168
|
+
if (!visible) {
|
|
169
|
+
this.detach();
|
|
170
|
+
return;
|
|
171
|
+
}
|
|
172
|
+
const badge = this.attach();
|
|
173
|
+
const dot = this.dot();
|
|
174
|
+
const srText = this.ariaLabel().trim();
|
|
175
|
+
this.renderer.setAttribute(badge, 'data-tone', this.tone());
|
|
176
|
+
this.renderer.setAttribute(badge, 'data-position', this.position());
|
|
177
|
+
if (dot) {
|
|
178
|
+
this.renderer.addClass(badge, 'mk-badge-overlay--dot');
|
|
179
|
+
}
|
|
180
|
+
else {
|
|
181
|
+
this.renderer.removeClass(badge, 'mk-badge-overlay--dot');
|
|
182
|
+
}
|
|
183
|
+
this.renderer.setProperty(badge, 'textContent', this.label());
|
|
184
|
+
// A dot has nothing to read; a labelled badge is described via the
|
|
185
|
+
// hidden span instead — either way the visual is hidden from AT.
|
|
186
|
+
if (dot || srText) {
|
|
187
|
+
this.renderer.setAttribute(badge, 'aria-hidden', 'true');
|
|
188
|
+
}
|
|
189
|
+
else {
|
|
190
|
+
this.renderer.removeAttribute(badge, 'aria-hidden');
|
|
191
|
+
}
|
|
192
|
+
this.syncSr(srText);
|
|
193
|
+
});
|
|
194
|
+
}
|
|
195
|
+
attach() {
|
|
196
|
+
if (this.badge)
|
|
197
|
+
return this.badge;
|
|
198
|
+
const el = this.host.nativeElement;
|
|
199
|
+
const view = this.document.defaultView;
|
|
200
|
+
const position = view?.getComputedStyle(el).position;
|
|
201
|
+
if (!position || position === 'static') {
|
|
202
|
+
this.renderer.setStyle(el, 'position', 'relative');
|
|
203
|
+
this.positionedHost = true;
|
|
204
|
+
}
|
|
205
|
+
const badge = this.renderer.createElement('span');
|
|
206
|
+
this.renderer.addClass(badge, 'mk-badge-overlay');
|
|
207
|
+
this.renderer.appendChild(el, badge);
|
|
208
|
+
this.badge = badge;
|
|
209
|
+
return badge;
|
|
210
|
+
}
|
|
211
|
+
detach() {
|
|
212
|
+
if (this.badge) {
|
|
213
|
+
this.renderer.removeChild(this.host.nativeElement, this.badge);
|
|
214
|
+
this.badge = null;
|
|
215
|
+
}
|
|
216
|
+
this.syncSr('');
|
|
217
|
+
if (this.positionedHost) {
|
|
218
|
+
this.renderer.removeStyle(this.host.nativeElement, 'position');
|
|
219
|
+
this.positionedHost = false;
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
/** Create / update / remove the hidden description and its aria-describedby link. */
|
|
223
|
+
syncSr(text) {
|
|
224
|
+
const el = this.host.nativeElement;
|
|
225
|
+
if (text) {
|
|
226
|
+
if (!this.sr) {
|
|
227
|
+
const sr = this.renderer.createElement('span');
|
|
228
|
+
this.renderer.addClass(sr, 'mk-visually-hidden');
|
|
229
|
+
this.renderer.setAttribute(sr, 'id', this.srId);
|
|
230
|
+
this.renderer.appendChild(el, sr);
|
|
231
|
+
this.sr = sr;
|
|
232
|
+
const ids = (el.getAttribute('aria-describedby') ?? '').split(/\s+/).filter(Boolean);
|
|
233
|
+
if (!ids.includes(this.srId))
|
|
234
|
+
ids.push(this.srId);
|
|
235
|
+
this.renderer.setAttribute(el, 'aria-describedby', ids.join(' '));
|
|
236
|
+
}
|
|
237
|
+
this.renderer.setProperty(this.sr, 'textContent', text);
|
|
238
|
+
}
|
|
239
|
+
else if (this.sr) {
|
|
240
|
+
this.renderer.removeChild(el, this.sr);
|
|
241
|
+
this.sr = null;
|
|
242
|
+
const ids = (el.getAttribute('aria-describedby') ?? '')
|
|
243
|
+
.split(/\s+/)
|
|
244
|
+
.filter((id) => id && id !== this.srId);
|
|
245
|
+
if (ids.length) {
|
|
246
|
+
this.renderer.setAttribute(el, 'aria-describedby', ids.join(' '));
|
|
247
|
+
}
|
|
248
|
+
else {
|
|
249
|
+
this.renderer.removeAttribute(el, 'aria-describedby');
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.7", ngImport: i0, type: MkBadgeOverlay, deps: [], target: i0.ɵɵFactoryTarget.Directive });
|
|
254
|
+
static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "22.0.7", type: MkBadgeOverlay, isStandalone: true, selector: "[mkBadgeOverlay]", inputs: { content: { classPropertyName: "content", publicName: "mkBadgeOverlay", isSignal: true, isRequired: false, transformFunction: null }, position: { classPropertyName: "position", publicName: "mkBadgeOverlayPosition", isSignal: true, isRequired: false, transformFunction: null }, tone: { classPropertyName: "tone", publicName: "mkBadgeOverlayTone", isSignal: true, isRequired: false, transformFunction: null }, dot: { classPropertyName: "dot", publicName: "mkBadgeOverlayDot", isSignal: true, isRequired: false, transformFunction: null }, max: { classPropertyName: "max", publicName: "mkBadgeOverlayMax", isSignal: true, isRequired: false, transformFunction: null }, hidden: { classPropertyName: "hidden", publicName: "mkBadgeOverlayHidden", isSignal: true, isRequired: false, transformFunction: null }, ariaLabel: { classPropertyName: "ariaLabel", publicName: "mkBadgeOverlayAriaLabel", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0 });
|
|
255
|
+
}
|
|
256
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.7", ngImport: i0, type: MkBadgeOverlay, decorators: [{
|
|
257
|
+
type: Directive,
|
|
258
|
+
args: [{
|
|
259
|
+
selector: '[mkBadgeOverlay]',
|
|
260
|
+
}]
|
|
261
|
+
}], ctorParameters: () => [], propDecorators: { content: [{ type: i0.Input, args: [{ isSignal: true, alias: "mkBadgeOverlay", required: false }] }], position: [{ type: i0.Input, args: [{ isSignal: true, alias: "mkBadgeOverlayPosition", required: false }] }], tone: [{ type: i0.Input, args: [{ isSignal: true, alias: "mkBadgeOverlayTone", required: false }] }], dot: [{ type: i0.Input, args: [{ isSignal: true, alias: "mkBadgeOverlayDot", required: false }] }], max: [{ type: i0.Input, args: [{ isSignal: true, alias: "mkBadgeOverlayMax", required: false }] }], hidden: [{ type: i0.Input, args: [{ isSignal: true, alias: "mkBadgeOverlayHidden", required: false }] }], ariaLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "mkBadgeOverlayAriaLabel", required: false }] }] } });
|
|
262
|
+
|
|
263
|
+
/**
|
|
264
|
+
* EmptyState — a centered placeholder for "nothing here yet" situations: empty
|
|
265
|
+
* tables, no search results, a fresh dashboard, a cleared inbox. Provide a
|
|
266
|
+
* `title` (and usually a `description`), an `icon` or projected media, and
|
|
267
|
+
* call-to-action buttons via the actions slot.
|
|
268
|
+
*
|
|
269
|
+
* Slots: `[mkEmptyStateMedia]` (custom illustration, overrides `icon`), default
|
|
270
|
+
* content (extra body), `[mkEmptyStateActions]` (buttons).
|
|
271
|
+
*
|
|
272
|
+
* ```html
|
|
273
|
+
* <mk-empty-state icon="search" title="No results"
|
|
274
|
+
* description="Try adjusting your filters.">
|
|
275
|
+
* <button mkButton mkEmptyStateActions variant="outline">Clear filters</button>
|
|
276
|
+
* </mk-empty-state>
|
|
277
|
+
* ```
|
|
278
|
+
*/
|
|
279
|
+
class MkEmptyState {
|
|
280
|
+
/** Name of a registered icon shown above the title (ignored if media is projected). */
|
|
281
|
+
icon = input('', /* @ts-ignore */
|
|
282
|
+
...(ngDevMode ? [{ debugName: "icon" }] : /* istanbul ignore next */ []));
|
|
283
|
+
/** Main heading, e.g. "No invoices yet". */
|
|
284
|
+
title = input('', /* @ts-ignore */
|
|
285
|
+
...(ngDevMode ? [{ debugName: "title" }] : /* istanbul ignore next */ []));
|
|
286
|
+
/** Supporting sentence under the title. */
|
|
287
|
+
description = input('', /* @ts-ignore */
|
|
288
|
+
...(ngDevMode ? [{ debugName: "description" }] : /* istanbul ignore next */ []));
|
|
289
|
+
/** Overall scale of the block. */
|
|
290
|
+
size = input('md', /* @ts-ignore */
|
|
291
|
+
...(ngDevMode ? [{ debugName: "size" }] : /* istanbul ignore next */ []));
|
|
292
|
+
iconSize = () => this.size() === 'sm' ? 28 : this.size() === 'lg' ? 48 : 36;
|
|
293
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.7", ngImport: i0, type: MkEmptyState, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
294
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.0.7", type: MkEmptyState, isStandalone: true, selector: "mk-empty-state", inputs: { icon: { classPropertyName: "icon", publicName: "icon", isSignal: true, isRequired: false, transformFunction: null }, title: { classPropertyName: "title", publicName: "title", isSignal: true, isRequired: false, transformFunction: null }, description: { classPropertyName: "description", publicName: "description", isSignal: true, isRequired: false, transformFunction: null }, size: { classPropertyName: "size", publicName: "size", isSignal: true, isRequired: false, transformFunction: null } }, host: { properties: { "class.mk-empty-state--sm": "size() === 'sm'", "class.mk-empty-state--lg": "size() === 'lg'" }, classAttribute: "mk-empty-state" }, ngImport: i0, template: "@if (icon()) {\n <span class=\"mk-empty-state__icon\" aria-hidden=\"true\">\n <mk-icon [name]=\"icon()\" [size]=\"iconSize()\" />\n </span>\n}\n<ng-content select=\"[mkEmptyStateMedia]\" />\n\n@if (title()) {\n <p class=\"mk-empty-state__title\">{{ title() }}</p>\n}\n@if (description()) {\n <p class=\"mk-empty-state__description\">{{ description() }}</p>\n}\n\n<ng-content />\n\n<div class=\"mk-empty-state__actions\">\n <ng-content select=\"[mkEmptyStateActions]\" />\n</div>\n", styles: [":host{display:flex;flex-direction:column;align-items:center;justify-content:center;gap:var(--mk-space-2);padding:var(--mk-space-8) var(--mk-space-5);text-align:center;font-family:var(--mk-font-sans);color:var(--mk-text)}:host(.mk-empty-state--sm){padding:var(--mk-space-5) var(--mk-space-4)}:host(.mk-empty-state--lg){padding:var(--mk-space-12) var(--mk-space-6)}.mk-empty-state__icon{display:inline-flex;align-items:center;justify-content:center;margin-bottom:var(--mk-space-1);color:var(--mk-text-subtle)}.mk-empty-state__title{margin:0;font-size:var(--mk-font-size-lg);font-weight:var(--mk-font-weight-semibold);line-height:var(--mk-line-height-snug);color:var(--mk-text)}:host(.mk-empty-state--sm) .mk-empty-state__title{font-size:var(--mk-font-size-md)}:host(.mk-empty-state--lg) .mk-empty-state__title{font-size:var(--mk-font-size-xl)}.mk-empty-state__description{margin:0;max-width:34ch;font-size:var(--mk-font-size-md);line-height:var(--mk-line-height-normal);color:var(--mk-text-muted)}.mk-empty-state__actions{display:flex;flex-wrap:wrap;align-items:center;justify-content:center;gap:var(--mk-space-2);margin-top:var(--mk-space-3)}.mk-empty-state__actions:empty{display:none}\n"], dependencies: [{ kind: "component", type: MkIcon, selector: "mk-icon", inputs: ["name", "size", "label"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
295
|
+
}
|
|
296
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.7", ngImport: i0, type: MkEmptyState, decorators: [{
|
|
297
|
+
type: Component,
|
|
298
|
+
args: [{ selector: 'mk-empty-state', changeDetection: ChangeDetectionStrategy.OnPush, imports: [MkIcon], host: {
|
|
299
|
+
class: 'mk-empty-state',
|
|
300
|
+
'[class.mk-empty-state--sm]': "size() === 'sm'",
|
|
301
|
+
'[class.mk-empty-state--lg]': "size() === 'lg'",
|
|
302
|
+
}, template: "@if (icon()) {\n <span class=\"mk-empty-state__icon\" aria-hidden=\"true\">\n <mk-icon [name]=\"icon()\" [size]=\"iconSize()\" />\n </span>\n}\n<ng-content select=\"[mkEmptyStateMedia]\" />\n\n@if (title()) {\n <p class=\"mk-empty-state__title\">{{ title() }}</p>\n}\n@if (description()) {\n <p class=\"mk-empty-state__description\">{{ description() }}</p>\n}\n\n<ng-content />\n\n<div class=\"mk-empty-state__actions\">\n <ng-content select=\"[mkEmptyStateActions]\" />\n</div>\n", styles: [":host{display:flex;flex-direction:column;align-items:center;justify-content:center;gap:var(--mk-space-2);padding:var(--mk-space-8) var(--mk-space-5);text-align:center;font-family:var(--mk-font-sans);color:var(--mk-text)}:host(.mk-empty-state--sm){padding:var(--mk-space-5) var(--mk-space-4)}:host(.mk-empty-state--lg){padding:var(--mk-space-12) var(--mk-space-6)}.mk-empty-state__icon{display:inline-flex;align-items:center;justify-content:center;margin-bottom:var(--mk-space-1);color:var(--mk-text-subtle)}.mk-empty-state__title{margin:0;font-size:var(--mk-font-size-lg);font-weight:var(--mk-font-weight-semibold);line-height:var(--mk-line-height-snug);color:var(--mk-text)}:host(.mk-empty-state--sm) .mk-empty-state__title{font-size:var(--mk-font-size-md)}:host(.mk-empty-state--lg) .mk-empty-state__title{font-size:var(--mk-font-size-xl)}.mk-empty-state__description{margin:0;max-width:34ch;font-size:var(--mk-font-size-md);line-height:var(--mk-line-height-normal);color:var(--mk-text-muted)}.mk-empty-state__actions{display:flex;flex-wrap:wrap;align-items:center;justify-content:center;gap:var(--mk-space-2);margin-top:var(--mk-space-3)}.mk-empty-state__actions:empty{display:none}\n"] }]
|
|
303
|
+
}], propDecorators: { icon: [{ type: i0.Input, args: [{ isSignal: true, alias: "icon", required: false }] }], title: [{ type: i0.Input, args: [{ isSignal: true, alias: "title", required: false }] }], description: [{ type: i0.Input, args: [{ isSignal: true, alias: "description", required: false }] }], size: [{ type: i0.Input, args: [{ isSignal: true, alias: "size", required: false }] }] } });
|
|
304
|
+
|
|
305
|
+
/**
|
|
306
|
+
* @mk-kit/ui/status — the small status indicators every other group leans on:
|
|
307
|
+
* spinner, badge (+ overlay) and empty state. They lived in `@mk-kit/ui/data`
|
|
308
|
+
* until 0.53; that entry still re-exports them, but `feedback` imports them
|
|
309
|
+
* from here so a dialog or toast service no longer drags the whole data group
|
|
310
|
+
* (charts, viewers, kanban → dnd) into an app's initial bundle.
|
|
311
|
+
*/
|
|
312
|
+
|
|
313
|
+
/**
|
|
314
|
+
* Generated bundle index. Do not edit.
|
|
315
|
+
*/
|
|
316
|
+
|
|
317
|
+
export { MkBadge, MkBadgeOverlay, MkEmptyState, MkSpinner };
|
|
318
|
+
//# sourceMappingURL=mk-kit-ui-status.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mk-kit-ui-status.mjs","sources":["../../../projects/mk-kit/status/spinner/spinner.ts","../../../projects/mk-kit/status/spinner/spinner.html","../../../projects/mk-kit/status/badge/badge.ts","../../../projects/mk-kit/status/badge/badge.html","../../../projects/mk-kit/status/badge/badge-overlay.ts","../../../projects/mk-kit/status/empty-state/empty-state.ts","../../../projects/mk-kit/status/empty-state/empty-state.html","../../../projects/mk-kit/status/index.ts","../../../projects/mk-kit/status/mk-kit-ui-status.ts"],"sourcesContent":["import { ChangeDetectionStrategy, Component, inject, input } from '@angular/core';\nimport { MK_I18N } from '@mk-kit/ui/core';\nimport type { MkSize, MkTone } from '@mk-kit/ui/core';\n\n/**\n * Spinner — a circular indeterminate loading indicator. Exposes `role=\"status\"`\n * with a visually-hidden label so assistive tech announces the loading state.\n * The animation slows under `prefers-reduced-motion`.\n *\n * ```html\n * <mk-spinner />\n * <mk-spinner size=\"lg\" tone=\"neutral\" label=\"Fetching results\" />\n * ```\n */\n@Component({\n selector: 'mk-spinner',\n templateUrl: './spinner.html',\n styleUrl: './spinner.scss',\n changeDetection: ChangeDetectionStrategy.OnPush,\n host: {\n class: 'mk-spinner',\n role: 'status',\n '[class.mk-spinner--sm]': \"size() === 'sm'\",\n '[class.mk-spinner--md]': \"size() === 'md'\",\n '[class.mk-spinner--lg]': \"size() === 'lg'\",\n '[attr.data-tone]': 'tone()',\n },\n})\nexport class MkSpinner {\n protected readonly i18n = inject(MK_I18N);\n\n /** Size scale. */\n readonly size = input<MkSize>('md');\n /** Semantic color tone. */\n readonly tone = input<MkTone>('primary');\n /** Visually-hidden status label announced to screen readers. */\n readonly label = input(this.i18n.loading);\n}\n","<span class=\"mk-spinner__circle\" aria-hidden=\"true\"></span>\n<span class=\"mk-spinner__sr\">{{ label() }}</span>\n","import {\n ChangeDetectionStrategy,\n Component,\n booleanAttribute,\n input,\n} from '@angular/core';\nimport type { MkSize, MkTone } from '@mk-kit/ui/core';\n\n/** Visual treatment for a {@link MkBadge}. */\nexport type MkBadgeVariant = 'solid' | 'soft' | 'outline';\n\n/**\n * Badge — a compact status pill, typically for counts or short state labels.\n * Set `dot` for a minimal notification indicator with no text.\n *\n * ```html\n * <mk-badge tone=\"success\">Active</mk-badge>\n * <mk-badge tone=\"danger\" variant=\"solid\">3</mk-badge>\n * <mk-badge tone=\"danger\" dot aria-label=\"Unread messages\" />\n * ```\n */\n@Component({\n selector: 'mk-badge',\n templateUrl: './badge.html',\n styleUrl: './badge.scss',\n changeDetection: ChangeDetectionStrategy.OnPush,\n host: {\n class: 'mk-badge',\n '[class.mk-badge--sm]': \"size() === 'sm'\",\n '[class.mk-badge--md]': \"size() === 'md'\",\n '[class.mk-badge--lg]': \"size() === 'lg'\",\n '[class.mk-badge--solid]': \"variant() === 'solid'\",\n '[class.mk-badge--soft]': \"variant() === 'soft'\",\n '[class.mk-badge--outline]': \"variant() === 'outline'\",\n '[class.mk-badge--dot]': 'dot()',\n '[attr.data-tone]': 'tone()',\n },\n})\nexport class MkBadge {\n /** Semantic color tone. */\n readonly tone = input<MkTone>('primary');\n /** Visual treatment. */\n readonly variant = input<MkBadgeVariant>('soft');\n /** Size scale. */\n readonly size = input<MkSize>('md');\n /** Render as a tiny dot (no text) for notification indicators. */\n readonly dot = input(false, { transform: booleanAttribute });\n}\n","@if (!dot()) {\n <ng-content />\n}\n","import {\n DOCUMENT,\n Directive,\n ElementRef,\n PLATFORM_ID,\n Renderer2,\n booleanAttribute,\n computed,\n effect,\n inject,\n input,\n numberAttribute,\n} from '@angular/core';\nimport { isPlatformBrowser } from '@angular/common';\nimport { mkUniqueId, type MkTone } from '@mk-kit/ui/core';\n\n/** Corner of the host an {@link MkBadgeOverlay} is anchored to. */\nexport type MkBadgeOverlayPosition =\n | 'top-end'\n | 'top-start'\n | 'bottom-end'\n | 'bottom-start';\n\n/**\n * Badge overlay — anchors a small badge (count, dot or short text) to a corner\n * of ANY element: an icon button, an avatar, a tab label. The host stays a\n * single tab stop; the badge is a decorative, non-focusable child.\n *\n * - Numbers above `mkBadgeOverlayMax` (default 99) collapse to `99+`.\n * - `mkBadgeOverlayDot` renders a textless dot (\"something is new\").\n * - `mkBadgeOverlayAriaLabel` is the screen-reader text (\"3 unread\"). It is\n * rendered in a visually hidden span and wired to the host with\n * `aria-describedby`, so it is announced after the host's own name even\n * when the host has an `aria-label`. When it is given, the visible badge is\n * `aria-hidden` so the count is not read twice.\n * - Positions use logical insets, so `top-end` sits at the top-right in LTR\n * and the top-left in RTL.\n *\n * The badge is painted with the global `.mk-badge-overlay` styles from\n * `@mk-kit/ui/styles.css` and follows the `--mk-*` tone tokens.\n *\n * ```html\n * <button mkButton iconOnly aria-label=\"Notifications\"\n * [mkBadgeOverlay]=\"unread()\" mkBadgeOverlayTone=\"danger\"\n * [mkBadgeOverlayAriaLabel]=\"unread() + ' unread'\">\n * <mk-icon name=\"bell\" />\n * </button>\n *\n * <mk-avatar name=\"Ada Lovelace\" mkBadgeOverlay mkBadgeOverlayDot\n * mkBadgeOverlayTone=\"success\" mkBadgeOverlayPosition=\"bottom-end\" />\n * ```\n */\n@Directive({\n selector: '[mkBadgeOverlay]',\n})\nexport class MkBadgeOverlay {\n private readonly host = inject<ElementRef<HTMLElement>>(ElementRef);\n private readonly renderer = inject(Renderer2);\n private readonly document = inject(DOCUMENT);\n private readonly isBrowser = isPlatformBrowser(inject(PLATFORM_ID));\n\n /**\n * Badge content — a count or a short label. `null` / empty hides the badge\n * unless `mkBadgeOverlayDot` is set. Numeric strings are treated as numbers\n * so `mkBadgeOverlay=\"120\"` also collapses to `99+`.\n */\n readonly content = input<string | number | null | undefined>(null, {\n alias: 'mkBadgeOverlay',\n });\n /** Corner the badge is anchored to (logical: `end` flips in RTL). */\n readonly position = input<MkBadgeOverlayPosition>('top-end', {\n alias: 'mkBadgeOverlayPosition',\n });\n /** Semantic color tone (same scale as `mk-badge`). */\n readonly tone = input<MkTone>('primary', { alias: 'mkBadgeOverlayTone' });\n /** Render a textless dot instead of the content. */\n readonly dot = input(false, {\n alias: 'mkBadgeOverlayDot',\n transform: booleanAttribute,\n });\n /** Numbers above this render as `<max>+`. `0` disables the cap. */\n readonly max = input(99, {\n alias: 'mkBadgeOverlayMax',\n transform: numberAttribute,\n });\n /** Hide the badge while keeping the directive (and its aria wiring) in place. */\n readonly hidden = input(false, {\n alias: 'mkBadgeOverlayHidden',\n transform: booleanAttribute,\n });\n /**\n * Screen-reader text for the badge, e.g. `\"3 unread\"`. Announced as the\n * host's description; the visible badge becomes `aria-hidden`.\n */\n readonly ariaLabel = input<string>('', { alias: 'mkBadgeOverlayAriaLabel' });\n\n /** The text painted in the badge (`''` in dot mode). */\n readonly label = computed<string>(() => {\n if (this.dot()) return '';\n const raw = this.content();\n if (raw === null || raw === undefined || raw === '') return '';\n const max = this.max();\n const n =\n typeof raw === 'number' ? raw : /^\\d+$/.test(raw) ? Number(raw) : NaN;\n if (Number.isFinite(n) && max > 0 && n > max) return `${max}+`;\n return String(raw);\n });\n\n /** Whether the badge is currently rendered. */\n readonly visible = computed(\n () => !this.hidden() && (this.dot() || this.label() !== ''),\n );\n\n private readonly srId = mkUniqueId('mk-badge-overlay');\n private badge: HTMLElement | null = null;\n private sr: HTMLElement | null = null;\n /** Set when WE made the host positioned, so we can undo it on removal. */\n private positionedHost = false;\n\n constructor() {\n if (!this.isBrowser) return;\n\n effect(() => {\n const visible = this.visible();\n if (!visible) {\n this.detach();\n return;\n }\n const badge = this.attach();\n const dot = this.dot();\n const srText = this.ariaLabel().trim();\n\n this.renderer.setAttribute(badge, 'data-tone', this.tone());\n this.renderer.setAttribute(badge, 'data-position', this.position());\n if (dot) {\n this.renderer.addClass(badge, 'mk-badge-overlay--dot');\n } else {\n this.renderer.removeClass(badge, 'mk-badge-overlay--dot');\n }\n this.renderer.setProperty(badge, 'textContent', this.label());\n // A dot has nothing to read; a labelled badge is described via the\n // hidden span instead — either way the visual is hidden from AT.\n if (dot || srText) {\n this.renderer.setAttribute(badge, 'aria-hidden', 'true');\n } else {\n this.renderer.removeAttribute(badge, 'aria-hidden');\n }\n this.syncSr(srText);\n });\n }\n\n private attach(): HTMLElement {\n if (this.badge) return this.badge;\n const el = this.host.nativeElement;\n const view = this.document.defaultView;\n const position = view?.getComputedStyle(el).position;\n if (!position || position === 'static') {\n this.renderer.setStyle(el, 'position', 'relative');\n this.positionedHost = true;\n }\n const badge: HTMLElement = this.renderer.createElement('span');\n this.renderer.addClass(badge, 'mk-badge-overlay');\n this.renderer.appendChild(el, badge);\n this.badge = badge;\n return badge;\n }\n\n private detach(): void {\n if (this.badge) {\n this.renderer.removeChild(this.host.nativeElement, this.badge);\n this.badge = null;\n }\n this.syncSr('');\n if (this.positionedHost) {\n this.renderer.removeStyle(this.host.nativeElement, 'position');\n this.positionedHost = false;\n }\n }\n\n /** Create / update / remove the hidden description and its aria-describedby link. */\n private syncSr(text: string): void {\n const el = this.host.nativeElement;\n if (text) {\n if (!this.sr) {\n const sr: HTMLElement = this.renderer.createElement('span');\n this.renderer.addClass(sr, 'mk-visually-hidden');\n this.renderer.setAttribute(sr, 'id', this.srId);\n this.renderer.appendChild(el, sr);\n this.sr = sr;\n const ids = (el.getAttribute('aria-describedby') ?? '').split(/\\s+/).filter(Boolean);\n if (!ids.includes(this.srId)) ids.push(this.srId);\n this.renderer.setAttribute(el, 'aria-describedby', ids.join(' '));\n }\n this.renderer.setProperty(this.sr, 'textContent', text);\n } else if (this.sr) {\n this.renderer.removeChild(el, this.sr);\n this.sr = null;\n const ids = (el.getAttribute('aria-describedby') ?? '')\n .split(/\\s+/)\n .filter((id) => id && id !== this.srId);\n if (ids.length) {\n this.renderer.setAttribute(el, 'aria-describedby', ids.join(' '));\n } else {\n this.renderer.removeAttribute(el, 'aria-describedby');\n }\n }\n }\n}\n","import {\n ChangeDetectionStrategy,\n Component,\n input,\n} from '@angular/core';\nimport type { MkSize } from '@mk-kit/ui/core';\nimport { MkIcon } from '@mk-kit/ui/icon';\n\n/**\n * EmptyState — a centered placeholder for \"nothing here yet\" situations: empty\n * tables, no search results, a fresh dashboard, a cleared inbox. Provide a\n * `title` (and usually a `description`), an `icon` or projected media, and\n * call-to-action buttons via the actions slot.\n *\n * Slots: `[mkEmptyStateMedia]` (custom illustration, overrides `icon`), default\n * content (extra body), `[mkEmptyStateActions]` (buttons).\n *\n * ```html\n * <mk-empty-state icon=\"search\" title=\"No results\"\n * description=\"Try adjusting your filters.\">\n * <button mkButton mkEmptyStateActions variant=\"outline\">Clear filters</button>\n * </mk-empty-state>\n * ```\n */\n@Component({\n selector: 'mk-empty-state',\n templateUrl: './empty-state.html',\n styleUrl: './empty-state.scss',\n changeDetection: ChangeDetectionStrategy.OnPush,\n imports: [MkIcon],\n host: {\n class: 'mk-empty-state',\n '[class.mk-empty-state--sm]': \"size() === 'sm'\",\n '[class.mk-empty-state--lg]': \"size() === 'lg'\",\n },\n})\nexport class MkEmptyState {\n /** Name of a registered icon shown above the title (ignored if media is projected). */\n readonly icon = input<string>('');\n /** Main heading, e.g. \"No invoices yet\". */\n readonly title = input<string>('');\n /** Supporting sentence under the title. */\n readonly description = input<string>('');\n /** Overall scale of the block. */\n readonly size = input<MkSize>('md');\n\n protected readonly iconSize = () =>\n this.size() === 'sm' ? 28 : this.size() === 'lg' ? 48 : 36;\n}\n","@if (icon()) {\n <span class=\"mk-empty-state__icon\" aria-hidden=\"true\">\n <mk-icon [name]=\"icon()\" [size]=\"iconSize()\" />\n </span>\n}\n<ng-content select=\"[mkEmptyStateMedia]\" />\n\n@if (title()) {\n <p class=\"mk-empty-state__title\">{{ title() }}</p>\n}\n@if (description()) {\n <p class=\"mk-empty-state__description\">{{ description() }}</p>\n}\n\n<ng-content />\n\n<div class=\"mk-empty-state__actions\">\n <ng-content select=\"[mkEmptyStateActions]\" />\n</div>\n","/**\n * @mk-kit/ui/status — the small status indicators every other group leans on:\n * spinner, badge (+ overlay) and empty state. They lived in `@mk-kit/ui/data`\n * until 0.53; that entry still re-exports them, but `feedback` imports them\n * from here so a dialog or toast service no longer drags the whole data group\n * (charts, viewers, kanban → dnd) into an app's initial bundle.\n */\nexport * from './spinner';\nexport * from './badge';\nexport * from './empty-state';\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './index';\n"],"names":[],"mappings":"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"}
|