@mk-kit/ui 0.41.0 → 0.43.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.
Files changed (53) hide show
  1. package/README.md +4 -4
  2. package/THIRD_PARTY_NOTICES.md +4 -2
  3. package/fesm2022/mk-kit-ui-block-editor.mjs +4 -2
  4. package/fesm2022/mk-kit-ui-block-editor.mjs.map +1 -1
  5. package/fesm2022/mk-kit-ui-checkbox.mjs +4 -2
  6. package/fesm2022/mk-kit-ui-checkbox.mjs.map +1 -1
  7. package/fesm2022/mk-kit-ui-core.mjs +218 -1
  8. package/fesm2022/mk-kit-ui-core.mjs.map +1 -1
  9. package/fesm2022/mk-kit-ui-data.mjs +801 -16
  10. package/fesm2022/mk-kit-ui-data.mjs.map +1 -1
  11. package/fesm2022/mk-kit-ui-datetime.mjs +90 -52
  12. package/fesm2022/mk-kit-ui-datetime.mjs.map +1 -1
  13. package/fesm2022/mk-kit-ui-directives.mjs +395 -2
  14. package/fesm2022/mk-kit-ui-directives.mjs.map +1 -1
  15. package/fesm2022/mk-kit-ui-dnd.mjs +183 -29
  16. package/fesm2022/mk-kit-ui-dnd.mjs.map +1 -1
  17. package/fesm2022/mk-kit-ui-dynamic-form.mjs +149 -2
  18. package/fesm2022/mk-kit-ui-dynamic-form.mjs.map +1 -1
  19. package/fesm2022/mk-kit-ui-feedback.mjs +1 -1
  20. package/fesm2022/mk-kit-ui-feedback.mjs.map +1 -1
  21. package/fesm2022/mk-kit-ui-forms.mjs +331 -81
  22. package/fesm2022/mk-kit-ui-forms.mjs.map +1 -1
  23. package/fesm2022/mk-kit-ui-icon-extended.mjs +425 -0
  24. package/fesm2022/mk-kit-ui-icon-extended.mjs.map +1 -0
  25. package/fesm2022/mk-kit-ui-icon.mjs +296 -459
  26. package/fesm2022/mk-kit-ui-icon.mjs.map +1 -1
  27. package/fesm2022/mk-kit-ui-query-builder.mjs +1 -1
  28. package/fesm2022/mk-kit-ui-query-builder.mjs.map +1 -1
  29. package/fesm2022/mk-kit-ui-rich-text.mjs +4 -2
  30. package/fesm2022/mk-kit-ui-rich-text.mjs.map +1 -1
  31. package/fesm2022/mk-kit-ui-table.mjs +36 -8
  32. package/fesm2022/mk-kit-ui-table.mjs.map +1 -1
  33. package/fesm2022/mk-kit-ui.mjs +1 -0
  34. package/fesm2022/mk-kit-ui.mjs.map +1 -1
  35. package/package.json +5 -1
  36. package/schematics/migrate-primeng/transform.js +4 -1
  37. package/schematics/ng-add/index.js +30 -2
  38. package/schematics/ng-add/schema.json +6 -0
  39. package/styles/mk-kit.css +604 -0
  40. package/types/mk-kit-ui-block-editor.d.ts +2 -0
  41. package/types/mk-kit-ui-checkbox.d.ts +2 -0
  42. package/types/mk-kit-ui-core.d.ts +119 -2
  43. package/types/mk-kit-ui-data.d.ts +359 -3
  44. package/types/mk-kit-ui-datetime.d.ts +41 -19
  45. package/types/mk-kit-ui-directives.d.ts +234 -3
  46. package/types/mk-kit-ui-dnd.d.ts +96 -14
  47. package/types/mk-kit-ui-dynamic-form.d.ts +44 -1
  48. package/types/mk-kit-ui-forms.d.ts +160 -20
  49. package/types/mk-kit-ui-icon-extended.d.ts +83 -0
  50. package/types/mk-kit-ui-icon.d.ts +100 -17
  51. package/types/mk-kit-ui-rich-text.d.ts +2 -0
  52. package/types/mk-kit-ui-table.d.ts +38 -21
  53. package/types/mk-kit-ui.d.ts +1 -0
@@ -1,8 +1,8 @@
1
1
  import * as i0 from '@angular/core';
2
- import { input, ChangeDetectionStrategy, Component, booleanAttribute, signal, computed, numberAttribute, contentChildren, ElementRef, effect, output, inject, DestroyRef, afterNextRender, DOCUMENT, PLATFORM_ID, Injector, viewChild, model, forwardRef, untracked, contentChild, TemplateRef, Directive, afterRenderEffect, ViewEncapsulation } from '@angular/core';
2
+ import { input, ChangeDetectionStrategy, Component, booleanAttribute, inject, ElementRef, Renderer2, DOCUMENT, PLATFORM_ID, numberAttribute, computed, effect, Directive, signal, contentChildren, output, TemplateRef, model, contentChild, linkedSignal, DestroyRef, afterNextRender, afterRenderEffect, untracked, Injector, viewChild, forwardRef, ViewEncapsulation } from '@angular/core';
3
+ import { isPlatformBrowser, NgTemplateOutlet, DOCUMENT as DOCUMENT$1 } from '@angular/common';
4
+ import { mkUniqueId, MK_I18N, MkFieldContext, mkInjectFieldTouched, mkHighlight } from '@mk-kit/ui/core';
3
5
  import { MkIcon } from '@mk-kit/ui/icon';
4
- import { mkUniqueId, MK_I18N, MkFieldContext, mkHighlight } from '@mk-kit/ui/core';
5
- import { isPlatformBrowser, NgTemplateOutlet } from '@angular/common';
6
6
  import { NG_VALUE_ACCESSOR } from '@angular/forms';
7
7
  import { MkCopyToClipboard } from '@mk-kit/ui/directives';
8
8
  import { mkMoveItemInArray, MkDropList, MkDrag } from '@mk-kit/ui/dnd';
@@ -151,6 +151,186 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.7", ngImpor
151
151
  }, 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"] }]
152
152
  }], 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 }] }] } });
153
153
 
154
+ /**
155
+ * Badge overlay — anchors a small badge (count, dot or short text) to a corner
156
+ * of ANY element: an icon button, an avatar, a tab label. The host stays a
157
+ * single tab stop; the badge is a decorative, non-focusable child.
158
+ *
159
+ * - Numbers above `mkBadgeOverlayMax` (default 99) collapse to `99+`.
160
+ * - `mkBadgeOverlayDot` renders a textless dot ("something is new").
161
+ * - `mkBadgeOverlayAriaLabel` is the screen-reader text ("3 unread"). It is
162
+ * rendered in a visually hidden span and wired to the host with
163
+ * `aria-describedby`, so it is announced after the host's own name even
164
+ * when the host has an `aria-label`. When it is given, the visible badge is
165
+ * `aria-hidden` so the count is not read twice.
166
+ * - Positions use logical insets, so `top-end` sits at the top-right in LTR
167
+ * and the top-left in RTL.
168
+ *
169
+ * The badge is painted with the global `.mk-badge-overlay` styles from
170
+ * `@mk-kit/ui/styles.css` and follows the `--mk-*` tone tokens.
171
+ *
172
+ * ```html
173
+ * <button mkButton iconOnly aria-label="Notifications"
174
+ * [mkBadgeOverlay]="unread()" mkBadgeOverlayTone="danger"
175
+ * [mkBadgeOverlayAriaLabel]="unread() + ' unread'">
176
+ * <mk-icon name="bell" />
177
+ * </button>
178
+ *
179
+ * <mk-avatar name="Ada Lovelace" mkBadgeOverlay mkBadgeOverlayDot
180
+ * mkBadgeOverlayTone="success" mkBadgeOverlayPosition="bottom-end" />
181
+ * ```
182
+ */
183
+ class MkBadgeOverlay {
184
+ host = inject(ElementRef);
185
+ renderer = inject(Renderer2);
186
+ document = inject(DOCUMENT);
187
+ isBrowser = isPlatformBrowser(inject(PLATFORM_ID));
188
+ /**
189
+ * Badge content — a count or a short label. `null` / empty hides the badge
190
+ * unless `mkBadgeOverlayDot` is set. Numeric strings are treated as numbers
191
+ * so `mkBadgeOverlay="120"` also collapses to `99+`.
192
+ */
193
+ content = input(null, { ...(ngDevMode ? { debugName: "content" } : /* istanbul ignore next */ {}), alias: 'mkBadgeOverlay' });
194
+ /** Corner the badge is anchored to (logical: `end` flips in RTL). */
195
+ position = input('top-end', { ...(ngDevMode ? { debugName: "position" } : /* istanbul ignore next */ {}), alias: 'mkBadgeOverlayPosition' });
196
+ /** Semantic color tone (same scale as `mk-badge`). */
197
+ tone = input('primary', { ...(ngDevMode ? { debugName: "tone" } : /* istanbul ignore next */ {}), alias: 'mkBadgeOverlayTone' });
198
+ /** Render a textless dot instead of the content. */
199
+ dot = input(false, { ...(ngDevMode ? { debugName: "dot" } : /* istanbul ignore next */ {}), alias: 'mkBadgeOverlayDot',
200
+ transform: booleanAttribute });
201
+ /** Numbers above this render as `<max>+`. `0` disables the cap. */
202
+ max = input(99, { ...(ngDevMode ? { debugName: "max" } : /* istanbul ignore next */ {}), alias: 'mkBadgeOverlayMax',
203
+ transform: numberAttribute });
204
+ /** Hide the badge while keeping the directive (and its aria wiring) in place. */
205
+ hidden = input(false, { ...(ngDevMode ? { debugName: "hidden" } : /* istanbul ignore next */ {}), alias: 'mkBadgeOverlayHidden',
206
+ transform: booleanAttribute });
207
+ /**
208
+ * Screen-reader text for the badge, e.g. `"3 unread"`. Announced as the
209
+ * host's description; the visible badge becomes `aria-hidden`.
210
+ */
211
+ ariaLabel = input('', { ...(ngDevMode ? { debugName: "ariaLabel" } : /* istanbul ignore next */ {}), alias: 'mkBadgeOverlayAriaLabel' });
212
+ /** The text painted in the badge (`''` in dot mode). */
213
+ label = computed(() => {
214
+ if (this.dot())
215
+ return '';
216
+ const raw = this.content();
217
+ if (raw === null || raw === undefined || raw === '')
218
+ return '';
219
+ const max = this.max();
220
+ const n = typeof raw === 'number' ? raw : /^\d+$/.test(raw) ? Number(raw) : NaN;
221
+ if (Number.isFinite(n) && max > 0 && n > max)
222
+ return `${max}+`;
223
+ return String(raw);
224
+ }, /* @ts-ignore */
225
+ ...(ngDevMode ? [{ debugName: "label" }] : /* istanbul ignore next */ []));
226
+ /** Whether the badge is currently rendered. */
227
+ visible = computed(() => !this.hidden() && (this.dot() || this.label() !== ''), /* @ts-ignore */
228
+ ...(ngDevMode ? [{ debugName: "visible" }] : /* istanbul ignore next */ []));
229
+ srId = mkUniqueId('mk-badge-overlay');
230
+ badge = null;
231
+ sr = null;
232
+ /** Set when WE made the host positioned, so we can undo it on removal. */
233
+ positionedHost = false;
234
+ constructor() {
235
+ if (!this.isBrowser)
236
+ return;
237
+ effect(() => {
238
+ const visible = this.visible();
239
+ if (!visible) {
240
+ this.detach();
241
+ return;
242
+ }
243
+ const badge = this.attach();
244
+ const dot = this.dot();
245
+ const srText = this.ariaLabel().trim();
246
+ this.renderer.setAttribute(badge, 'data-tone', this.tone());
247
+ this.renderer.setAttribute(badge, 'data-position', this.position());
248
+ if (dot) {
249
+ this.renderer.addClass(badge, 'mk-badge-overlay--dot');
250
+ }
251
+ else {
252
+ this.renderer.removeClass(badge, 'mk-badge-overlay--dot');
253
+ }
254
+ this.renderer.setProperty(badge, 'textContent', this.label());
255
+ // A dot has nothing to read; a labelled badge is described via the
256
+ // hidden span instead — either way the visual is hidden from AT.
257
+ if (dot || srText) {
258
+ this.renderer.setAttribute(badge, 'aria-hidden', 'true');
259
+ }
260
+ else {
261
+ this.renderer.removeAttribute(badge, 'aria-hidden');
262
+ }
263
+ this.syncSr(srText);
264
+ });
265
+ }
266
+ attach() {
267
+ if (this.badge)
268
+ return this.badge;
269
+ const el = this.host.nativeElement;
270
+ const view = this.document.defaultView;
271
+ const position = view?.getComputedStyle(el).position;
272
+ if (!position || position === 'static') {
273
+ this.renderer.setStyle(el, 'position', 'relative');
274
+ this.positionedHost = true;
275
+ }
276
+ const badge = this.renderer.createElement('span');
277
+ this.renderer.addClass(badge, 'mk-badge-overlay');
278
+ this.renderer.appendChild(el, badge);
279
+ this.badge = badge;
280
+ return badge;
281
+ }
282
+ detach() {
283
+ if (this.badge) {
284
+ this.renderer.removeChild(this.host.nativeElement, this.badge);
285
+ this.badge = null;
286
+ }
287
+ this.syncSr('');
288
+ if (this.positionedHost) {
289
+ this.renderer.removeStyle(this.host.nativeElement, 'position');
290
+ this.positionedHost = false;
291
+ }
292
+ }
293
+ /** Create / update / remove the hidden description and its aria-describedby link. */
294
+ syncSr(text) {
295
+ const el = this.host.nativeElement;
296
+ if (text) {
297
+ if (!this.sr) {
298
+ const sr = this.renderer.createElement('span');
299
+ this.renderer.addClass(sr, 'mk-visually-hidden');
300
+ this.renderer.setAttribute(sr, 'id', this.srId);
301
+ this.renderer.appendChild(el, sr);
302
+ this.sr = sr;
303
+ const ids = (el.getAttribute('aria-describedby') ?? '').split(/\s+/).filter(Boolean);
304
+ if (!ids.includes(this.srId))
305
+ ids.push(this.srId);
306
+ this.renderer.setAttribute(el, 'aria-describedby', ids.join(' '));
307
+ }
308
+ this.renderer.setProperty(this.sr, 'textContent', text);
309
+ }
310
+ else if (this.sr) {
311
+ this.renderer.removeChild(el, this.sr);
312
+ this.sr = null;
313
+ const ids = (el.getAttribute('aria-describedby') ?? '')
314
+ .split(/\s+/)
315
+ .filter((id) => id && id !== this.srId);
316
+ if (ids.length) {
317
+ this.renderer.setAttribute(el, 'aria-describedby', ids.join(' '));
318
+ }
319
+ else {
320
+ this.renderer.removeAttribute(el, 'aria-describedby');
321
+ }
322
+ }
323
+ }
324
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.7", ngImport: i0, type: MkBadgeOverlay, deps: [], target: i0.ɵɵFactoryTarget.Directive });
325
+ 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 });
326
+ }
327
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.7", ngImport: i0, type: MkBadgeOverlay, decorators: [{
328
+ type: Directive,
329
+ args: [{
330
+ selector: '[mkBadgeOverlay]',
331
+ }]
332
+ }], 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 }] }] } });
333
+
154
334
  /**
155
335
  * Tag — a non-interactive label for categories, keywords or metadata. Unlike
156
336
  * {@link MkChip} it carries no interaction; use it purely for display.
@@ -500,6 +680,434 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.7", ngImpor
500
680
  }, template: "<div class=\"mk-timeline-item__marker\">\n <span class=\"mk-timeline-item__dot\">\n @if (icon()) {\n <mk-icon [name]=\"icon()\" [size]=\"14\" />\n }\n </span>\n <span class=\"mk-timeline-item__connector\" aria-hidden=\"true\"></span>\n</div>\n\n<div class=\"mk-timeline-item__content\">\n @if (time()) {\n <span class=\"mk-timeline-item__time\">{{ time() }}</span>\n }\n @if (heading()) {\n <p class=\"mk-timeline-item__heading\">{{ heading() }}</p>\n }\n <div class=\"mk-timeline-item__body\">\n <ng-content />\n </div>\n</div>\n", styles: [":host{--_dot: var(--mk-primary);--_marker: 1.75rem;display:flex;gap:var(--mk-space-3);font-family:var(--mk-font-sans);color:var(--mk-text)}:host([data-tone=primary]){--_dot: var(--mk-primary)}:host([data-tone=success]){--_dot: var(--mk-success)}:host([data-tone=warning]){--_dot: var(--mk-warning)}:host([data-tone=danger]){--_dot: var(--mk-danger)}:host([data-tone=info]){--_dot: var(--mk-info)}:host([data-tone=neutral]){--_dot: var(--mk-text-muted)}.mk-timeline-item__marker{position:relative;flex:none;display:flex;justify-content:center;width:var(--_marker)}.mk-timeline-item__dot{position:relative;z-index:1;display:inline-flex;align-items:center;justify-content:center;width:.75rem;height:.75rem;margin-top:.5rem;border-radius:var(--mk-radius-circle);background-color:var(--_dot);color:var(--mk-primary-contrast);box-shadow:0 0 0 3px var(--mk-surface)}:host(.mk-timeline-item--icon) .mk-timeline-item__dot{width:var(--_marker);height:var(--_marker);margin-top:0;color:var(--_dot);background-color:color-mix(in srgb,var(--_dot) 16%,var(--mk-surface));box-shadow:0 0 0 3px var(--mk-surface),inset 0 0 0 1.5px color-mix(in srgb,var(--_dot) 40%,transparent)}.mk-timeline-item__connector{position:absolute;top:var(--_marker);bottom:0;left:50%;width:2px;transform:translate(-50%);background-color:var(--mk-border)}:host(:last-child) .mk-timeline-item__connector{display:none}.mk-timeline-item__content{flex:1 1 auto;min-width:0;padding-bottom:var(--mk-space-5)}:host(:last-child) .mk-timeline-item__content{padding-bottom:0}.mk-timeline-item__time{display:block;font-size:var(--mk-font-size-xs);font-weight:var(--mk-font-weight-medium);color:var(--mk-text-subtle)}.mk-timeline-item__heading{margin:0;font-size:var(--mk-font-size-md);font-weight:var(--mk-font-weight-semibold);line-height:var(--mk-line-height-snug);color:var(--mk-text)}.mk-timeline-item__body{margin-top:var(--mk-space-1);font-size:var(--mk-font-size-md);line-height:var(--mk-line-height-normal);color:var(--mk-text-muted)}.mk-timeline-item__body:empty{display:none}\n"] }]
501
681
  }], propDecorators: { tone: [{ type: i0.Input, args: [{ isSignal: true, alias: "tone", required: false }] }], icon: [{ type: i0.Input, args: [{ isSignal: true, alias: "icon", required: false }] }], time: [{ type: i0.Input, args: [{ isSignal: true, alias: "time", required: false }] }], heading: [{ type: i0.Input, args: [{ isSignal: true, alias: "heading", required: false }] }] } });
502
682
 
683
+ /**
684
+ * Build the nested `nodes` input from a flat `parentId` list (the shape most
685
+ * HR / directory APIs return). Row order is preserved among siblings; rows
686
+ * whose `parentId` does not match any row become roots.
687
+ *
688
+ * ```ts
689
+ * const nodes = mkOrgChartFromFlat([
690
+ * { id: 'ceo', label: 'Ada' },
691
+ * { id: 'cto', label: 'Grace', parentId: 'ceo' },
692
+ * ]);
693
+ * ```
694
+ */
695
+ function mkOrgChartFromFlat(list) {
696
+ const byId = new Map();
697
+ for (const row of list) {
698
+ const node = { id: row.id };
699
+ if (row.label !== undefined)
700
+ node.label = row.label;
701
+ if (row.data !== undefined)
702
+ node.data = row.data;
703
+ if (row.expanded !== undefined)
704
+ node.expanded = row.expanded;
705
+ byId.set(row.id, node);
706
+ }
707
+ const roots = [];
708
+ for (const row of list) {
709
+ const node = byId.get(row.id);
710
+ const parent = row.parentId != null ? byId.get(row.parentId) : undefined;
711
+ if (parent && parent !== node)
712
+ (parent.children ??= []).push(node);
713
+ else
714
+ roots.push(node);
715
+ }
716
+ return roots;
717
+ }
718
+ /**
719
+ * Custom node card for `mk-org-chart`:
720
+ *
721
+ * ```html
722
+ * <mk-org-chart [nodes]="nodes">
723
+ * <ng-template mkOrgChartNodeDef let-node let-selected="selected">
724
+ * <strong>{{ node.label }}</strong> — {{ node.data?.title }}
725
+ * </ng-template>
726
+ * </mk-org-chart>
727
+ * ```
728
+ *
729
+ * Bind the same array you pass to `nodes` to get a typed `node.data` in the
730
+ * template: `<ng-template [mkOrgChartNodeDef]="nodes" let-node>`.
731
+ */
732
+ class MkOrgChartNodeDef {
733
+ /**
734
+ * Type-inference hook only (the value is not used at runtime): bind the
735
+ * `nodes` array so `let-node` is typed as `MkOrgChartNode<T>`.
736
+ */
737
+ mkOrgChartNodeDef = input(undefined, /* @ts-ignore */
738
+ ...(ngDevMode ? [{ debugName: "mkOrgChartNodeDef" }] : /* istanbul ignore next */ []));
739
+ template = inject((TemplateRef));
740
+ static ngTemplateContextGuard(_dir, ctx) {
741
+ return true;
742
+ }
743
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.7", ngImport: i0, type: MkOrgChartNodeDef, deps: [], target: i0.ɵɵFactoryTarget.Directive });
744
+ static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "22.0.7", type: MkOrgChartNodeDef, isStandalone: true, selector: "ng-template[mkOrgChartNodeDef]", inputs: { mkOrgChartNodeDef: { classPropertyName: "mkOrgChartNodeDef", publicName: "mkOrgChartNodeDef", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0 });
745
+ }
746
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.7", ngImport: i0, type: MkOrgChartNodeDef, decorators: [{
747
+ type: Directive,
748
+ args: [{ selector: 'ng-template[mkOrgChartNodeDef]' }]
749
+ }], propDecorators: { mkOrgChartNodeDef: [{ type: i0.Input, args: [{ isSignal: true, alias: "mkOrgChartNodeDef", required: false }] }] } });
750
+ /**
751
+ * Organisation chart — a reporting-line hierarchy drawn with plain nested
752
+ * lists and CSS connectors (no canvas, prints and themes like everything
753
+ * else). Feed it a tree (`nodes`) or convert a flat `parentId` list with
754
+ * {@link mkOrgChartFromFlat}. Nodes render as a default card (avatar /
755
+ * initials, label, `data.title`) or through an `mkOrgChartNodeDef` template.
756
+ *
757
+ * Follows the ARIA tree pattern (`role="tree"` / `treeitem` / `group`, one
758
+ * roving tab stop). Keyboard (top-down; the axes swap for `orientation="left"`
759
+ * and in RTL): Down = first child (expands a collapsed node first), Up =
760
+ * parent, Left/Right = previous/next sibling, Home/End = first/last visible
761
+ * node, Enter/Space = select (or toggle when not selectable), `*` = expand
762
+ * all siblings, `+`/`-` = expand/collapse.
763
+ *
764
+ * ```html
765
+ * <mk-org-chart
766
+ * [nodes]="company"
767
+ * selectable
768
+ * [(selected)]="personId"
769
+ * collapsible
770
+ * (nodeClick)="open($event)"
771
+ * />
772
+ * ```
773
+ */
774
+ class MkOrgChart {
775
+ host = inject(ElementRef);
776
+ document = inject(DOCUMENT);
777
+ /** Localised strings (override globally via `provideMkI18n`). */
778
+ i18n = inject(MK_I18N);
779
+ /** The hierarchy to render (roots first). */
780
+ nodes = input([], /* @ts-ignore */
781
+ ...(ngDevMode ? [{ debugName: "nodes" }] : /* istanbul ignore next */ []));
782
+ /** Root at the top (children below) or at the inline start (children to the side). */
783
+ orientation = input('top', /* @ts-ignore */
784
+ ...(ngDevMode ? [{ debugName: "orientation" }] : /* istanbul ignore next */ []));
785
+ /** Allow choosing a node (adds selection styling + `aria-selected`). */
786
+ selectable = input(false, { ...(ngDevMode ? { debugName: "selectable" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
787
+ /** Show a toggle on every parent so branches can be hidden. */
788
+ collapsible = input(false, { ...(ngDevMode ? { debugName: "collapsible" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
789
+ /** Scale factor applied to the whole chart (clamped to 0.5–2). */
790
+ zoom = input(1, { ...(ngDevMode ? { debugName: "zoom" } : /* istanbul ignore next */ {}), transform: numberAttribute });
791
+ /** Accessible name for the tree. */
792
+ ariaLabel = input(this.i18n.orgChartLabel, { ...(ngDevMode ? { debugName: "ariaLabel" } : /* istanbul ignore next */ {}), alias: 'aria-label' });
793
+ /** Two-way selected node id (`null` = nothing selected). */
794
+ selected = model(null, /* @ts-ignore */
795
+ ...(ngDevMode ? [{ debugName: "selected" }] : /* istanbul ignore next */ []));
796
+ /**
797
+ * Two-way ids of the expanded parents. Leave unbound to let the chart
798
+ * manage expansion itself (seeded from each node's `expanded` flag).
799
+ */
800
+ expanded = model(undefined, /* @ts-ignore */
801
+ ...(ngDevMode ? [{ debugName: "expanded" }] : /* istanbul ignore next */ []));
802
+ /** Emits the node whose card was clicked or activated with Enter/Space. */
803
+ nodeClick = output();
804
+ /** Emits whenever a node is expanded or collapsed. */
805
+ nodeToggle = output();
806
+ nodeDef = contentChild((MkOrgChartNodeDef), /* @ts-ignore */
807
+ ...(ngDevMode ? [{ debugName: "nodeDef" }] : /* istanbul ignore next */ []));
808
+ zoomLevel = computed(() => {
809
+ const z = this.zoom();
810
+ return Number.isFinite(z) ? Math.min(2, Math.max(0.5, z)) : 1;
811
+ }, /* @ts-ignore */
812
+ ...(ngDevMode ? [{ debugName: "zoomLevel" }] : /* istanbul ignore next */ []));
813
+ /**
814
+ * Expanded parent ids. Controlled by `expanded` when bound; otherwise kept
815
+ * locally — a node's `expanded` flag only seeds ids not present in the
816
+ * previous `nodes` value, so re-emitting the array never reverts branches
817
+ * the user has since toggled.
818
+ */
819
+ expandedIds = linkedSignal({ ...(ngDevMode ? { debugName: "expandedIds" } : /* istanbul ignore next */ {}), source: () => ({ nodes: this.nodes(), expanded: this.expanded() }),
820
+ computation: ({ nodes, expanded }, previous) => {
821
+ if (expanded)
822
+ return new Set(expanded);
823
+ const prev = previous?.value;
824
+ const known = previous ? collectIds(previous.source.nodes) : null;
825
+ const next = new Set();
826
+ walk(nodes, (node) => {
827
+ if (!node.children?.length)
828
+ return;
829
+ const isKnown = known?.has(node.id) ?? false;
830
+ if (isKnown ? prev.has(node.id) : node.expanded !== false)
831
+ next.add(node.id);
832
+ });
833
+ return next;
834
+ } });
835
+ /** Id of the node holding the roving tab stop. */
836
+ activeId = signal(null, /* @ts-ignore */
837
+ ...(ngDevMode ? [{ debugName: "activeId" }] : /* istanbul ignore next */ []));
838
+ /** Visible nodes in DOM (pre-order) order. */
839
+ rows = computed(() => {
840
+ const collapsible = this.collapsible();
841
+ const expandedIds = this.expandedIds();
842
+ const out = [];
843
+ const visit = (list, depth, parentId) => {
844
+ const siblings = list.map((n) => n.id);
845
+ for (const node of list) {
846
+ const hasChildren = !!node.children?.length;
847
+ const expanded = hasChildren && (!collapsible || expandedIds.has(node.id));
848
+ out.push({ node, depth, parentId, siblings, hasChildren, expanded });
849
+ if (expanded)
850
+ visit(node.children, depth + 1, node.id);
851
+ }
852
+ };
853
+ visit(this.nodes(), 1, null);
854
+ return out;
855
+ }, /* @ts-ignore */
856
+ ...(ngDevMode ? [{ debugName: "rows" }] : /* istanbul ignore next */ []));
857
+ rowById = computed(() => new Map(this.rows().map((r) => [r.node.id, r])), /* @ts-ignore */
858
+ ...(ngDevMode ? [{ debugName: "rowById" }] : /* istanbul ignore next */ []));
859
+ /** The single id with `tabindex="0"` (falls back to the first visible node). */
860
+ tabStopId = computed(() => {
861
+ const active = this.activeId();
862
+ if (active !== null && this.rowById().has(active))
863
+ return active;
864
+ return this.rows()[0]?.node.id ?? null;
865
+ }, /* @ts-ignore */
866
+ ...(ngDevMode ? [{ debugName: "tabStopId" }] : /* istanbul ignore next */ []));
867
+ // ---- template helpers --------------------------------------------------
868
+ isExpanded(node) {
869
+ if (!node.children?.length)
870
+ return false;
871
+ return !this.collapsible() || this.expandedIds().has(node.id);
872
+ }
873
+ isSelected(node) {
874
+ return this.selectable() && this.selected() === node.id;
875
+ }
876
+ tabIndexFor(node) {
877
+ return this.tabStopId() === node.id ? 0 : -1;
878
+ }
879
+ toggleLabel(node) {
880
+ const tpl = this.isExpanded(node) ? this.i18n.orgChartCollapse : this.i18n.orgChartExpand;
881
+ return tpl.replace('{label}', node.label ?? node.id);
882
+ }
883
+ context(node, depth) {
884
+ return {
885
+ $implicit: node,
886
+ node,
887
+ depth,
888
+ expanded: this.isExpanded(node),
889
+ selected: this.isSelected(node),
890
+ };
891
+ }
892
+ /** `data.title` / `data.avatar` of the default card, read defensively. */
893
+ field(node, key) {
894
+ const data = node.data;
895
+ const value = data?.[key];
896
+ return typeof value === 'string' && value ? value : undefined;
897
+ }
898
+ // ---- state changes -----------------------------------------------------
899
+ /** Expand or collapse a parent (no-op for leaves / non-collapsible charts). */
900
+ toggle(node) {
901
+ this.setExpanded(node, !this.isExpanded(node));
902
+ }
903
+ /** Expand or collapse a parent explicitly. */
904
+ setExpanded(node, expanded) {
905
+ if (!this.collapsible() || !node.children?.length)
906
+ return;
907
+ if (this.expandedIds().has(node.id) === expanded)
908
+ return;
909
+ const next = new Set(this.expandedIds());
910
+ if (expanded)
911
+ next.add(node.id);
912
+ else
913
+ next.delete(node.id);
914
+ this.expandedIds.set(next);
915
+ this.expanded.set([...next]);
916
+ this.nodeToggle.emit({ node, expanded });
917
+ }
918
+ /** Select a node by reference (no-op unless `selectable`). */
919
+ select(node) {
920
+ if (!this.selectable())
921
+ return;
922
+ this.selected.set(node.id);
923
+ }
924
+ activate(node) {
925
+ this.activeId.set(node.id);
926
+ if (this.selectable())
927
+ this.select(node);
928
+ this.nodeClick.emit(node);
929
+ }
930
+ onCardClick(event, node) {
931
+ event.stopPropagation();
932
+ this.activate(node);
933
+ }
934
+ onToggleClick(event, node) {
935
+ event.stopPropagation();
936
+ this.activeId.set(node.id);
937
+ this.toggle(node);
938
+ this.focusItem(node.id);
939
+ }
940
+ /** Keeps the roving tab stop on whichever item last received focus. */
941
+ onFocusIn(event) {
942
+ const id = this.itemIdOf(event.target);
943
+ if (id !== null)
944
+ this.activeId.set(id);
945
+ }
946
+ onKeydown(event) {
947
+ if (!(event instanceof KeyboardEvent))
948
+ return;
949
+ const id = this.itemIdOf(event.target);
950
+ if (id === null)
951
+ return;
952
+ const row = this.rowById().get(id);
953
+ if (!row)
954
+ return;
955
+ const node = row.node;
956
+ const intent = this.intentOf(event.key);
957
+ switch (intent) {
958
+ case 'into':
959
+ event.preventDefault();
960
+ if (row.hasChildren && !row.expanded) {
961
+ this.setExpanded(node, true);
962
+ }
963
+ else if (row.expanded) {
964
+ this.focusItem(node.children[0].id);
965
+ }
966
+ return;
967
+ case 'parent':
968
+ event.preventDefault();
969
+ if (row.parentId !== null)
970
+ this.focusItem(row.parentId);
971
+ return;
972
+ case 'next':
973
+ case 'prev': {
974
+ event.preventDefault();
975
+ const i = row.siblings.indexOf(id);
976
+ const target = row.siblings[intent === 'next' ? i + 1 : i - 1];
977
+ if (target !== undefined)
978
+ this.focusItem(target);
979
+ return;
980
+ }
981
+ }
982
+ switch (event.key) {
983
+ case 'Home':
984
+ event.preventDefault();
985
+ this.focusItem(this.rows()[0]?.node.id ?? null);
986
+ break;
987
+ case 'End': {
988
+ event.preventDefault();
989
+ const rows = this.rows();
990
+ this.focusItem(rows[rows.length - 1]?.node.id ?? null);
991
+ break;
992
+ }
993
+ case 'Enter':
994
+ case ' ':
995
+ event.preventDefault();
996
+ if (!this.selectable() && row.hasChildren && this.collapsible()) {
997
+ this.toggle(node);
998
+ }
999
+ this.activate(node);
1000
+ break;
1001
+ case '*': {
1002
+ event.preventDefault();
1003
+ const nodes = this.siblingsOf(row);
1004
+ for (const sibling of nodes)
1005
+ this.setExpanded(sibling, true);
1006
+ break;
1007
+ }
1008
+ case '+':
1009
+ case '=':
1010
+ event.preventDefault();
1011
+ this.setExpanded(node, true);
1012
+ break;
1013
+ case '-':
1014
+ event.preventDefault();
1015
+ this.setExpanded(node, false);
1016
+ break;
1017
+ }
1018
+ }
1019
+ /**
1020
+ * Map an arrow key to a tree direction. Top-down: Down = into, Up = parent,
1021
+ * Left/Right = siblings (mirrored in RTL). Left-to-right: Right = into,
1022
+ * Left = parent (mirrored in RTL), Up/Down = siblings.
1023
+ */
1024
+ intentOf(key) {
1025
+ const rtl = this.isRtl();
1026
+ if (this.orientation() === 'left') {
1027
+ switch (key) {
1028
+ case 'ArrowRight':
1029
+ return rtl ? 'parent' : 'into';
1030
+ case 'ArrowLeft':
1031
+ return rtl ? 'into' : 'parent';
1032
+ case 'ArrowDown':
1033
+ return 'next';
1034
+ case 'ArrowUp':
1035
+ return 'prev';
1036
+ }
1037
+ return null;
1038
+ }
1039
+ switch (key) {
1040
+ case 'ArrowDown':
1041
+ return 'into';
1042
+ case 'ArrowUp':
1043
+ return 'parent';
1044
+ case 'ArrowRight':
1045
+ return rtl ? 'prev' : 'next';
1046
+ case 'ArrowLeft':
1047
+ return rtl ? 'next' : 'prev';
1048
+ }
1049
+ return null;
1050
+ }
1051
+ siblingsOf(row) {
1052
+ const list = row.parentId === null
1053
+ ? this.nodes()
1054
+ : (this.rowById().get(row.parentId)?.node.children ?? []);
1055
+ return list.filter((n) => !!n.children?.length);
1056
+ }
1057
+ isRtl() {
1058
+ const el = this.host.nativeElement;
1059
+ const dir = el.closest('[dir]')?.getAttribute('dir');
1060
+ if (dir)
1061
+ return dir.toLowerCase() === 'rtl';
1062
+ const view = this.document.defaultView;
1063
+ return (view?.getComputedStyle(el).direction ?? 'ltr') === 'rtl';
1064
+ }
1065
+ itemIdOf(target) {
1066
+ if (!(target instanceof Element))
1067
+ return null;
1068
+ const item = target.closest('.mk-org-chart__item');
1069
+ if (!item || !this.host.nativeElement.contains(item))
1070
+ return null;
1071
+ return item.dataset['mkId'] ?? null;
1072
+ }
1073
+ focusItem(id) {
1074
+ if (id === null)
1075
+ return;
1076
+ this.activeId.set(id);
1077
+ const items = this.host.nativeElement.querySelectorAll('.mk-org-chart__item');
1078
+ for (const item of Array.from(items)) {
1079
+ if (item.dataset['mkId'] === id) {
1080
+ item.focus();
1081
+ return;
1082
+ }
1083
+ }
1084
+ }
1085
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.7", ngImport: i0, type: MkOrgChart, deps: [], target: i0.ɵɵFactoryTarget.Component });
1086
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.0.7", type: MkOrgChart, isStandalone: true, selector: "mk-org-chart", inputs: { nodes: { classPropertyName: "nodes", publicName: "nodes", isSignal: true, isRequired: false, transformFunction: null }, orientation: { classPropertyName: "orientation", publicName: "orientation", isSignal: true, isRequired: false, transformFunction: null }, selectable: { classPropertyName: "selectable", publicName: "selectable", isSignal: true, isRequired: false, transformFunction: null }, collapsible: { classPropertyName: "collapsible", publicName: "collapsible", isSignal: true, isRequired: false, transformFunction: null }, zoom: { classPropertyName: "zoom", publicName: "zoom", isSignal: true, isRequired: false, transformFunction: null }, ariaLabel: { classPropertyName: "ariaLabel", publicName: "aria-label", isSignal: true, isRequired: false, transformFunction: null }, selected: { classPropertyName: "selected", publicName: "selected", isSignal: true, isRequired: false, transformFunction: null }, expanded: { classPropertyName: "expanded", publicName: "expanded", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { selected: "selectedChange", expanded: "expandedChange", nodeClick: "nodeClick", nodeToggle: "nodeToggle" }, host: { properties: { "class.mk-org-chart--top": "orientation() === 'top'", "class.mk-org-chart--left": "orientation() === 'left'", "class.mk-org-chart--selectable": "selectable()", "class.mk-org-chart--collapsible": "collapsible()" }, classAttribute: "mk-org-chart" }, queries: [{ propertyName: "nodeDef", first: true, predicate: (MkOrgChartNodeDef), descendants: true, isSignal: true }], exportAs: ["mkOrgChart"], ngImport: i0, template: "<div class=\"mk-org-chart__scroller\">\n <div class=\"mk-org-chart__canvas\" [style.zoom]=\"zoomLevel()\">\n <ul\n class=\"mk-org-chart__level mk-org-chart__level--root\"\n role=\"tree\"\n [attr.aria-label]=\"ariaLabel() || null\"\n (keydown)=\"onKeydown($event)\"\n (focusin)=\"onFocusIn($event)\"\n >\n @for (node of nodes(); track node.id) {\n <ng-container\n *ngTemplateOutlet=\"itemTpl; context: { node: node, depth: 1 }\"\n />\n }\n </ul>\n </div>\n</div>\n\n<ng-template #itemTpl let-node=\"node\" let-depth=\"depth\">\n <li\n class=\"mk-org-chart__item\"\n role=\"treeitem\"\n [attr.data-mk-id]=\"node.id\"\n [class.mk-org-chart__item--expanded]=\"isExpanded(node)\"\n [class.mk-org-chart__item--collapsed]=\"node.children?.length && !isExpanded(node)\"\n [attr.aria-level]=\"depth\"\n [attr.aria-expanded]=\"node.children?.length ? isExpanded(node) : null\"\n [attr.aria-selected]=\"selectable() ? isSelected(node) : null\"\n [attr.tabindex]=\"tabIndexFor(node)\"\n >\n <div\n class=\"mk-org-chart__node\"\n [class.mk-org-chart__node--selected]=\"isSelected(node)\"\n [class.mk-org-chart__node--custom]=\"!!nodeDef()\"\n (click)=\"onCardClick($event, node)\"\n >\n @if (nodeDef(); as def) {\n <ng-container\n *ngTemplateOutlet=\"def.template; context: context(node, depth)\"\n />\n } @else {\n <mk-avatar\n class=\"mk-org-chart__avatar\"\n size=\"sm\"\n [name]=\"node.label ?? node.id\"\n [src]=\"field(node, 'avatar')\"\n alt=\"\"\n aria-hidden=\"true\"\n />\n <span class=\"mk-org-chart__text\">\n <span class=\"mk-org-chart__label\">{{ node.label ?? node.id }}</span>\n @if (field(node, 'title'); as title) {\n <span class=\"mk-org-chart__title\">{{ title }}</span>\n }\n </span>\n }\n @if (collapsible() && node.children?.length) {\n <button\n type=\"button\"\n class=\"mk-org-chart__toggle\"\n tabindex=\"-1\"\n [attr.aria-label]=\"toggleLabel(node)\"\n [attr.aria-expanded]=\"isExpanded(node)\"\n (click)=\"onToggleClick($event, node)\"\n >\n <span class=\"mk-org-chart__caret\" aria-hidden=\"true\"></span>\n </button>\n }\n </div>\n @if (isExpanded(node)) {\n <ul class=\"mk-org-chart__level mk-org-chart__level--nested\" role=\"group\">\n @for (child of node.children; track child.id) {\n <ng-container\n *ngTemplateOutlet=\"itemTpl; context: { node: child, depth: depth + 1 }\"\n />\n }\n </ul>\n }\n </li>\n</ng-template>\n", styles: ["@charset \"UTF-8\";:host{--_line: var(--mk-border-strong);--_line-w: var(--mk-border-width);--_gap-main: var(--mk-space-8);--_gap-cross: var(--mk-space-4);--_card-w: 11rem;display:block;font-family:var(--mk-font-sans);color:var(--mk-text)}.mk-org-chart__scroller{overflow:auto;max-width:100%}.mk-org-chart__canvas{display:inline-block;min-width:100%;padding:var(--mk-space-2);box-sizing:border-box}.mk-org-chart__level{display:flex;list-style:none;margin:0;padding:0;position:relative}.mk-org-chart__level--root{justify-content:center}.mk-org-chart__item{position:relative;display:flex;align-items:center;outline:none}:host(.mk-org-chart--top) .mk-org-chart__level{flex-direction:row}:host(.mk-org-chart--top) .mk-org-chart__level--nested{padding-block-start:var(--_gap-main)}:host(.mk-org-chart--top) .mk-org-chart__level--nested:before{content:\"\";position:absolute;top:0;inset-inline-start:50%;width:0;height:var(--_gap-main);border-inline-start:var(--_line-w) solid var(--_line)}:host(.mk-org-chart--top) .mk-org-chart__item{flex-direction:column;padding:var(--_gap-main) calc(var(--_gap-cross) / 2) 0}:host(.mk-org-chart--top) .mk-org-chart__item:before,:host(.mk-org-chart--top) .mk-org-chart__item:after{content:\"\";position:absolute;top:0;width:50%;height:var(--_gap-main);border-block-start:var(--_line-w) solid var(--_line);pointer-events:none}:host(.mk-org-chart--top) .mk-org-chart__item:before{inset-inline-end:50%}:host(.mk-org-chart--top) .mk-org-chart__item:after{inset-inline-start:50%;border-inline-start:var(--_line-w) solid var(--_line)}:host(.mk-org-chart--top) .mk-org-chart__item:first-child:before{display:none}:host(.mk-org-chart--top) .mk-org-chart__item:last-child:after{border-block-start-color:transparent}:host(.mk-org-chart--top) .mk-org-chart__level--root>.mk-org-chart__item{padding-block-start:0}:host(.mk-org-chart--top) .mk-org-chart__level--root>.mk-org-chart__item:before,:host(.mk-org-chart--top) .mk-org-chart__level--root>.mk-org-chart__item:after{display:none}:host(.mk-org-chart--left) .mk-org-chart__level{flex-direction:column}:host(.mk-org-chart--left) .mk-org-chart__level--root{align-items:flex-start}:host(.mk-org-chart--left) .mk-org-chart__level--nested{padding-inline-start:var(--_gap-main)}:host(.mk-org-chart--left) .mk-org-chart__level--nested:before{content:\"\";position:absolute;top:50%;inset-inline-start:0;width:var(--_gap-main);height:0;border-block-start:var(--_line-w) solid var(--_line)}:host(.mk-org-chart--left) .mk-org-chart__item{flex-direction:row;padding-block:calc(var(--_gap-cross) / 2);padding-inline:var(--_gap-main) 0}:host(.mk-org-chart--left) .mk-org-chart__item:before,:host(.mk-org-chart--left) .mk-org-chart__item:after{content:\"\";position:absolute;inset-inline-start:0;width:var(--_gap-main);height:50%;border-inline-start:var(--_line-w) solid var(--_line);pointer-events:none}:host(.mk-org-chart--left) .mk-org-chart__item:before{top:0}:host(.mk-org-chart--left) .mk-org-chart__item:after{top:50%;border-block-start:var(--_line-w) solid var(--_line)}:host(.mk-org-chart--left) .mk-org-chart__item:first-child:before{display:none}:host(.mk-org-chart--left) .mk-org-chart__item:last-child:after{border-inline-start-color:transparent}:host(.mk-org-chart--left) .mk-org-chart__level--root>.mk-org-chart__item{padding-inline-start:0}:host(.mk-org-chart--left) .mk-org-chart__level--root>.mk-org-chart__item:before,:host(.mk-org-chart--left) .mk-org-chart__level--root>.mk-org-chart__item:after{display:none}.mk-org-chart__node{position:relative;z-index:1;display:flex;align-items:center;gap:var(--mk-space-3);box-sizing:border-box;min-width:var(--_card-w);max-width:calc(var(--_card-w) * 2);min-height:2.75rem;padding:var(--mk-space-2) var(--mk-space-3);border:var(--mk-border-width) solid var(--mk-border);border-radius:var(--mk-radius-md);background:var(--mk-surface);box-shadow:var(--mk-shadow-xs);text-align:start;transition:border-color var(--mk-duration-fast) var(--mk-ease-standard),background-color var(--mk-duration-fast) var(--mk-ease-standard),box-shadow var(--mk-duration-fast) var(--mk-ease-standard)}.mk-org-chart__node--custom{display:block;min-width:0;max-width:none;min-height:0;padding:0;border:0;background:transparent;box-shadow:none}:host(.mk-org-chart--selectable) .mk-org-chart__node{cursor:pointer;-webkit-user-select:none;user-select:none}:host(.mk-org-chart--selectable) .mk-org-chart__node:not(.mk-org-chart__node--custom):hover{border-color:var(--mk-border-strong);background-color:color-mix(in srgb,var(--mk-surface),var(--mk-hover-overlay))}.mk-org-chart__node--selected:not(.mk-org-chart__node--custom),:host(.mk-org-chart--selectable) .mk-org-chart__node--selected:not(.mk-org-chart__node--custom):hover{border-color:var(--mk-primary);background-color:var(--mk-primary-subtle);box-shadow:0 0 0 1px var(--mk-primary)}.mk-org-chart__item:focus-visible>.mk-org-chart__node{outline:var(--mk-focus-ring-width) solid var(--mk-focus-ring);outline-offset:var(--mk-focus-ring-offset);border-radius:var(--mk-radius-md)}.mk-org-chart__avatar{flex:none}.mk-org-chart__text{display:flex;flex-direction:column;min-width:0;line-height:var(--mk-line-height-snug)}.mk-org-chart__label{font-size:var(--mk-font-size-sm);font-weight:var(--mk-font-weight-semibold);color:var(--mk-text);overflow-wrap:anywhere}.mk-org-chart__title{font-size:var(--mk-font-size-xs);color:var(--mk-text-muted);overflow-wrap:anywhere}.mk-org-chart__node--selected .mk-org-chart__label{color:var(--mk-primary-subtle-text)}.mk-org-chart__toggle{position:absolute;z-index:2;display:grid;place-items:center;width:1.25rem;height:1.25rem;padding:0;margin:0;border:var(--mk-border-width) solid var(--mk-border-strong);border-radius:var(--mk-radius-circle);background:var(--mk-surface);color:var(--mk-text-muted);cursor:pointer;transition:background-color var(--mk-duration-fast) var(--mk-ease-standard),color var(--mk-duration-fast) var(--mk-ease-standard)}@media(pointer:coarse){.mk-org-chart__toggle:after{content:\"\";position:absolute;inset:min(0px,(100% - 24px) / 2)}}.mk-org-chart__toggle:hover{background:var(--mk-surface-2);color:var(--mk-text)}.mk-org-chart__toggle:focus-visible{outline:var(--mk-focus-ring-width) solid var(--mk-focus-ring);outline-offset:var(--mk-focus-ring-offset)}:host(.mk-org-chart--top) .mk-org-chart__toggle{bottom:0;left:50%;transform:translate(-50%,50%)}:host(.mk-org-chart--left) .mk-org-chart__toggle{top:50%;inset-inline-end:0;transform:translateY(-50%);margin-inline-end:-.625rem}.mk-org-chart__caret{width:.35rem;height:.35rem;border-inline-end:2px solid currentColor;border-block-end:2px solid currentColor;transition:transform var(--mk-duration-fast) var(--mk-ease-standard)}:host(.mk-org-chart--top) .mk-org-chart__caret{transform:translateY(-1px) rotate(45deg)}:host(.mk-org-chart--top) .mk-org-chart__item--expanded>.mk-org-chart__node>.mk-org-chart__toggle .mk-org-chart__caret{transform:translateY(1px) rotate(-135deg)}:host(.mk-org-chart--left) .mk-org-chart__caret{transform:translate(-1px) rotate(-45deg)}:host(.mk-org-chart--left) .mk-org-chart__item--expanded>.mk-org-chart__node>.mk-org-chart__toggle .mk-org-chart__caret{transform:translate(1px) rotate(135deg)}:host(.mk-org-chart--left:dir(rtl)) .mk-org-chart__caret{transform:translate(1px) rotate(135deg)}:host(.mk-org-chart--left:dir(rtl)) .mk-org-chart__item--expanded>.mk-org-chart__node>.mk-org-chart__toggle .mk-org-chart__caret{transform:translate(-1px) rotate(-45deg)}@media(prefers-reduced-motion:reduce){.mk-org-chart__node,.mk-org-chart__toggle,.mk-org-chart__caret{transition:none}}@media print{.mk-org-chart__scroller{overflow:visible}.mk-org-chart__canvas{display:block;zoom:1!important}.mk-org-chart__node{box-shadow:none;break-inside:avoid}.mk-org-chart__toggle{display:none}}\n"], dependencies: [{ kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "component", type: MkAvatar, selector: "mk-avatar", inputs: ["src", "name", "alt", "size", "shape", "status"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
1087
+ }
1088
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.7", ngImport: i0, type: MkOrgChart, decorators: [{
1089
+ type: Component,
1090
+ args: [{ selector: 'mk-org-chart', exportAs: 'mkOrgChart', changeDetection: ChangeDetectionStrategy.OnPush, imports: [NgTemplateOutlet, MkAvatar], host: {
1091
+ class: 'mk-org-chart',
1092
+ '[class.mk-org-chart--top]': "orientation() === 'top'",
1093
+ '[class.mk-org-chart--left]': "orientation() === 'left'",
1094
+ '[class.mk-org-chart--selectable]': 'selectable()',
1095
+ '[class.mk-org-chart--collapsible]': 'collapsible()',
1096
+ }, template: "<div class=\"mk-org-chart__scroller\">\n <div class=\"mk-org-chart__canvas\" [style.zoom]=\"zoomLevel()\">\n <ul\n class=\"mk-org-chart__level mk-org-chart__level--root\"\n role=\"tree\"\n [attr.aria-label]=\"ariaLabel() || null\"\n (keydown)=\"onKeydown($event)\"\n (focusin)=\"onFocusIn($event)\"\n >\n @for (node of nodes(); track node.id) {\n <ng-container\n *ngTemplateOutlet=\"itemTpl; context: { node: node, depth: 1 }\"\n />\n }\n </ul>\n </div>\n</div>\n\n<ng-template #itemTpl let-node=\"node\" let-depth=\"depth\">\n <li\n class=\"mk-org-chart__item\"\n role=\"treeitem\"\n [attr.data-mk-id]=\"node.id\"\n [class.mk-org-chart__item--expanded]=\"isExpanded(node)\"\n [class.mk-org-chart__item--collapsed]=\"node.children?.length && !isExpanded(node)\"\n [attr.aria-level]=\"depth\"\n [attr.aria-expanded]=\"node.children?.length ? isExpanded(node) : null\"\n [attr.aria-selected]=\"selectable() ? isSelected(node) : null\"\n [attr.tabindex]=\"tabIndexFor(node)\"\n >\n <div\n class=\"mk-org-chart__node\"\n [class.mk-org-chart__node--selected]=\"isSelected(node)\"\n [class.mk-org-chart__node--custom]=\"!!nodeDef()\"\n (click)=\"onCardClick($event, node)\"\n >\n @if (nodeDef(); as def) {\n <ng-container\n *ngTemplateOutlet=\"def.template; context: context(node, depth)\"\n />\n } @else {\n <mk-avatar\n class=\"mk-org-chart__avatar\"\n size=\"sm\"\n [name]=\"node.label ?? node.id\"\n [src]=\"field(node, 'avatar')\"\n alt=\"\"\n aria-hidden=\"true\"\n />\n <span class=\"mk-org-chart__text\">\n <span class=\"mk-org-chart__label\">{{ node.label ?? node.id }}</span>\n @if (field(node, 'title'); as title) {\n <span class=\"mk-org-chart__title\">{{ title }}</span>\n }\n </span>\n }\n @if (collapsible() && node.children?.length) {\n <button\n type=\"button\"\n class=\"mk-org-chart__toggle\"\n tabindex=\"-1\"\n [attr.aria-label]=\"toggleLabel(node)\"\n [attr.aria-expanded]=\"isExpanded(node)\"\n (click)=\"onToggleClick($event, node)\"\n >\n <span class=\"mk-org-chart__caret\" aria-hidden=\"true\"></span>\n </button>\n }\n </div>\n @if (isExpanded(node)) {\n <ul class=\"mk-org-chart__level mk-org-chart__level--nested\" role=\"group\">\n @for (child of node.children; track child.id) {\n <ng-container\n *ngTemplateOutlet=\"itemTpl; context: { node: child, depth: depth + 1 }\"\n />\n }\n </ul>\n }\n </li>\n</ng-template>\n", styles: ["@charset \"UTF-8\";:host{--_line: var(--mk-border-strong);--_line-w: var(--mk-border-width);--_gap-main: var(--mk-space-8);--_gap-cross: var(--mk-space-4);--_card-w: 11rem;display:block;font-family:var(--mk-font-sans);color:var(--mk-text)}.mk-org-chart__scroller{overflow:auto;max-width:100%}.mk-org-chart__canvas{display:inline-block;min-width:100%;padding:var(--mk-space-2);box-sizing:border-box}.mk-org-chart__level{display:flex;list-style:none;margin:0;padding:0;position:relative}.mk-org-chart__level--root{justify-content:center}.mk-org-chart__item{position:relative;display:flex;align-items:center;outline:none}:host(.mk-org-chart--top) .mk-org-chart__level{flex-direction:row}:host(.mk-org-chart--top) .mk-org-chart__level--nested{padding-block-start:var(--_gap-main)}:host(.mk-org-chart--top) .mk-org-chart__level--nested:before{content:\"\";position:absolute;top:0;inset-inline-start:50%;width:0;height:var(--_gap-main);border-inline-start:var(--_line-w) solid var(--_line)}:host(.mk-org-chart--top) .mk-org-chart__item{flex-direction:column;padding:var(--_gap-main) calc(var(--_gap-cross) / 2) 0}:host(.mk-org-chart--top) .mk-org-chart__item:before,:host(.mk-org-chart--top) .mk-org-chart__item:after{content:\"\";position:absolute;top:0;width:50%;height:var(--_gap-main);border-block-start:var(--_line-w) solid var(--_line);pointer-events:none}:host(.mk-org-chart--top) .mk-org-chart__item:before{inset-inline-end:50%}:host(.mk-org-chart--top) .mk-org-chart__item:after{inset-inline-start:50%;border-inline-start:var(--_line-w) solid var(--_line)}:host(.mk-org-chart--top) .mk-org-chart__item:first-child:before{display:none}:host(.mk-org-chart--top) .mk-org-chart__item:last-child:after{border-block-start-color:transparent}:host(.mk-org-chart--top) .mk-org-chart__level--root>.mk-org-chart__item{padding-block-start:0}:host(.mk-org-chart--top) .mk-org-chart__level--root>.mk-org-chart__item:before,:host(.mk-org-chart--top) .mk-org-chart__level--root>.mk-org-chart__item:after{display:none}:host(.mk-org-chart--left) .mk-org-chart__level{flex-direction:column}:host(.mk-org-chart--left) .mk-org-chart__level--root{align-items:flex-start}:host(.mk-org-chart--left) .mk-org-chart__level--nested{padding-inline-start:var(--_gap-main)}:host(.mk-org-chart--left) .mk-org-chart__level--nested:before{content:\"\";position:absolute;top:50%;inset-inline-start:0;width:var(--_gap-main);height:0;border-block-start:var(--_line-w) solid var(--_line)}:host(.mk-org-chart--left) .mk-org-chart__item{flex-direction:row;padding-block:calc(var(--_gap-cross) / 2);padding-inline:var(--_gap-main) 0}:host(.mk-org-chart--left) .mk-org-chart__item:before,:host(.mk-org-chart--left) .mk-org-chart__item:after{content:\"\";position:absolute;inset-inline-start:0;width:var(--_gap-main);height:50%;border-inline-start:var(--_line-w) solid var(--_line);pointer-events:none}:host(.mk-org-chart--left) .mk-org-chart__item:before{top:0}:host(.mk-org-chart--left) .mk-org-chart__item:after{top:50%;border-block-start:var(--_line-w) solid var(--_line)}:host(.mk-org-chart--left) .mk-org-chart__item:first-child:before{display:none}:host(.mk-org-chart--left) .mk-org-chart__item:last-child:after{border-inline-start-color:transparent}:host(.mk-org-chart--left) .mk-org-chart__level--root>.mk-org-chart__item{padding-inline-start:0}:host(.mk-org-chart--left) .mk-org-chart__level--root>.mk-org-chart__item:before,:host(.mk-org-chart--left) .mk-org-chart__level--root>.mk-org-chart__item:after{display:none}.mk-org-chart__node{position:relative;z-index:1;display:flex;align-items:center;gap:var(--mk-space-3);box-sizing:border-box;min-width:var(--_card-w);max-width:calc(var(--_card-w) * 2);min-height:2.75rem;padding:var(--mk-space-2) var(--mk-space-3);border:var(--mk-border-width) solid var(--mk-border);border-radius:var(--mk-radius-md);background:var(--mk-surface);box-shadow:var(--mk-shadow-xs);text-align:start;transition:border-color var(--mk-duration-fast) var(--mk-ease-standard),background-color var(--mk-duration-fast) var(--mk-ease-standard),box-shadow var(--mk-duration-fast) var(--mk-ease-standard)}.mk-org-chart__node--custom{display:block;min-width:0;max-width:none;min-height:0;padding:0;border:0;background:transparent;box-shadow:none}:host(.mk-org-chart--selectable) .mk-org-chart__node{cursor:pointer;-webkit-user-select:none;user-select:none}:host(.mk-org-chart--selectable) .mk-org-chart__node:not(.mk-org-chart__node--custom):hover{border-color:var(--mk-border-strong);background-color:color-mix(in srgb,var(--mk-surface),var(--mk-hover-overlay))}.mk-org-chart__node--selected:not(.mk-org-chart__node--custom),:host(.mk-org-chart--selectable) .mk-org-chart__node--selected:not(.mk-org-chart__node--custom):hover{border-color:var(--mk-primary);background-color:var(--mk-primary-subtle);box-shadow:0 0 0 1px var(--mk-primary)}.mk-org-chart__item:focus-visible>.mk-org-chart__node{outline:var(--mk-focus-ring-width) solid var(--mk-focus-ring);outline-offset:var(--mk-focus-ring-offset);border-radius:var(--mk-radius-md)}.mk-org-chart__avatar{flex:none}.mk-org-chart__text{display:flex;flex-direction:column;min-width:0;line-height:var(--mk-line-height-snug)}.mk-org-chart__label{font-size:var(--mk-font-size-sm);font-weight:var(--mk-font-weight-semibold);color:var(--mk-text);overflow-wrap:anywhere}.mk-org-chart__title{font-size:var(--mk-font-size-xs);color:var(--mk-text-muted);overflow-wrap:anywhere}.mk-org-chart__node--selected .mk-org-chart__label{color:var(--mk-primary-subtle-text)}.mk-org-chart__toggle{position:absolute;z-index:2;display:grid;place-items:center;width:1.25rem;height:1.25rem;padding:0;margin:0;border:var(--mk-border-width) solid var(--mk-border-strong);border-radius:var(--mk-radius-circle);background:var(--mk-surface);color:var(--mk-text-muted);cursor:pointer;transition:background-color var(--mk-duration-fast) var(--mk-ease-standard),color var(--mk-duration-fast) var(--mk-ease-standard)}@media(pointer:coarse){.mk-org-chart__toggle:after{content:\"\";position:absolute;inset:min(0px,(100% - 24px) / 2)}}.mk-org-chart__toggle:hover{background:var(--mk-surface-2);color:var(--mk-text)}.mk-org-chart__toggle:focus-visible{outline:var(--mk-focus-ring-width) solid var(--mk-focus-ring);outline-offset:var(--mk-focus-ring-offset)}:host(.mk-org-chart--top) .mk-org-chart__toggle{bottom:0;left:50%;transform:translate(-50%,50%)}:host(.mk-org-chart--left) .mk-org-chart__toggle{top:50%;inset-inline-end:0;transform:translateY(-50%);margin-inline-end:-.625rem}.mk-org-chart__caret{width:.35rem;height:.35rem;border-inline-end:2px solid currentColor;border-block-end:2px solid currentColor;transition:transform var(--mk-duration-fast) var(--mk-ease-standard)}:host(.mk-org-chart--top) .mk-org-chart__caret{transform:translateY(-1px) rotate(45deg)}:host(.mk-org-chart--top) .mk-org-chart__item--expanded>.mk-org-chart__node>.mk-org-chart__toggle .mk-org-chart__caret{transform:translateY(1px) rotate(-135deg)}:host(.mk-org-chart--left) .mk-org-chart__caret{transform:translate(-1px) rotate(-45deg)}:host(.mk-org-chart--left) .mk-org-chart__item--expanded>.mk-org-chart__node>.mk-org-chart__toggle .mk-org-chart__caret{transform:translate(1px) rotate(135deg)}:host(.mk-org-chart--left:dir(rtl)) .mk-org-chart__caret{transform:translate(1px) rotate(135deg)}:host(.mk-org-chart--left:dir(rtl)) .mk-org-chart__item--expanded>.mk-org-chart__node>.mk-org-chart__toggle .mk-org-chart__caret{transform:translate(-1px) rotate(-45deg)}@media(prefers-reduced-motion:reduce){.mk-org-chart__node,.mk-org-chart__toggle,.mk-org-chart__caret{transition:none}}@media print{.mk-org-chart__scroller{overflow:visible}.mk-org-chart__canvas{display:block;zoom:1!important}.mk-org-chart__node{box-shadow:none;break-inside:avoid}.mk-org-chart__toggle{display:none}}\n"] }]
1097
+ }], propDecorators: { nodes: [{ type: i0.Input, args: [{ isSignal: true, alias: "nodes", required: false }] }], orientation: [{ type: i0.Input, args: [{ isSignal: true, alias: "orientation", required: false }] }], selectable: [{ type: i0.Input, args: [{ isSignal: true, alias: "selectable", required: false }] }], collapsible: [{ type: i0.Input, args: [{ isSignal: true, alias: "collapsible", required: false }] }], zoom: [{ type: i0.Input, args: [{ isSignal: true, alias: "zoom", required: false }] }], ariaLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "aria-label", required: false }] }], selected: [{ type: i0.Input, args: [{ isSignal: true, alias: "selected", required: false }] }, { type: i0.Output, args: ["selectedChange"] }], expanded: [{ type: i0.Input, args: [{ isSignal: true, alias: "expanded", required: false }] }, { type: i0.Output, args: ["expandedChange"] }], nodeClick: [{ type: i0.Output, args: ["nodeClick"] }], nodeToggle: [{ type: i0.Output, args: ["nodeToggle"] }], nodeDef: [{ type: i0.ContentChild, args: [i0.forwardRef(() => MkOrgChartNodeDef), { isSignal: true }] }] } });
1098
+ function walk(list, fn) {
1099
+ for (const node of list) {
1100
+ fn(node);
1101
+ if (node.children?.length)
1102
+ walk(node.children, fn);
1103
+ }
1104
+ }
1105
+ function collectIds(list) {
1106
+ const ids = new Set();
1107
+ walk(list, (n) => ids.add(n.id));
1108
+ return ids;
1109
+ }
1110
+
503
1111
  /**
504
1112
  * Stat card — a compact KPI tile for dashboards. Shows a label, a primary
505
1113
  * value and an optional trend delta. The trend is conveyed by an arrow glyph
@@ -1165,6 +1773,15 @@ function mkChartTapPin(apply) {
1165
1773
  */
1166
1774
  const CHAR_PX = 6.2;
1167
1775
  const estimateLabelPx = (label) => label.length * CHAR_PX;
1776
+ /**
1777
+ * Fraction of its band a label may fill before `auto` tilts the axis.
1778
+ *
1779
+ * Not 1.0: labels that *technically* fit still read as a cramped run of words
1780
+ * with no gap between them ("mar" "kwi" "maj" touching each other), which is
1781
+ * the look tilting exists to avoid. Leaving a fifth of the band as breathing
1782
+ * room tilts the tight cases and leaves genuinely roomy axes alone.
1783
+ */
1784
+ const TILT_THRESHOLD = 0.8;
1168
1785
  /**
1169
1786
  * BarChart — compares a measure across categories with one or more series
1170
1787
  * (grouped or `stacked`), `vertical` (default) or `horizontal`. Dependency-free
@@ -1257,7 +1874,7 @@ class MkBarChart {
1257
1874
  if (!count)
1258
1875
  return 0;
1259
1876
  const band = Math.max(this.drawWidth() - 58, 1) / count;
1260
- return this.widestLabelPx() <= band ? 0 : 45;
1877
+ return this.widestLabelPx() <= band * TILT_THRESHOLD ? 0 : 45;
1261
1878
  }, /* @ts-ignore */
1262
1879
  ...(ngDevMode ? [{ debugName: "resolvedAngle" }] : /* istanbul ignore next */ []));
1263
1880
  /**
@@ -2222,18 +2839,105 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.7", ngImpor
2222
2839
  }, template: "<div class=\"mk-chart__frame\">\n <svg\n class=\"mk-chart__svg\"\n [attr.viewBox]=\"'0 0 ' + width() + ' ' + height()\"\n preserveAspectRatio=\"xMidYMid meet\"\n aria-hidden=\"true\"\n focusable=\"false\"\n >\n <!-- Horizontal gridlines + y-axis labels -->\n @for (row of yGrid(); track row.value) {\n @if (showGrid()) {\n <line\n class=\"mk-chart__grid\"\n [attr.x1]=\"row.x1\"\n [attr.x2]=\"row.x2\"\n [attr.y1]=\"row.y\"\n [attr.y2]=\"row.y\"\n />\n }\n <text\n class=\"mk-chart__axis-label mk-chart__axis-label--y\"\n [attr.x]=\"plot().x - 8\"\n [attr.y]=\"row.y\"\n >\n {{ row.label }}\n </text>\n }\n\n <!-- x-axis labels -->\n @for (col of xGrid(); track col.value) {\n <text\n class=\"mk-chart__axis-label mk-chart__axis-label--x\"\n [attr.x]=\"col.x\"\n [attr.y]=\"height() - 12\"\n >\n {{ col.label }}\n </text>\n }\n\n <!-- Axis titles -->\n @if (xLabel()) {\n <text\n class=\"mk-chart__axis-title mk-chart__axis-title--x\"\n [attr.x]=\"plot().x + plot().w / 2\"\n [attr.y]=\"height() - 1\"\n >\n {{ xLabel() }}\n </text>\n }\n @if (yLabel()) {\n <text\n class=\"mk-chart__axis-title mk-chart__axis-title--y\"\n [attr.transform]=\"'rotate(-90 10 ' + (plot().y + plot().h / 2) + ')'\"\n [attr.x]=\"10\"\n [attr.y]=\"plot().y + plot().h / 2\"\n >\n {{ yLabel() }}\n </text>\n }\n\n <!-- Points -->\n @for (p of points(); track $index; let i = $index) {\n <circle\n class=\"mk-chart__point\"\n [class.mk-chart__point--active]=\"hoverKey() === keyOf(i)\"\n [attr.cx]=\"p.cx\"\n [attr.cy]=\"p.cy\"\n [attr.r]=\"p.r\"\n [style.fill]=\"p.color\"\n (pointerenter)=\"setHover(keyOf(i))\"\n (pointerleave)=\"setHover(null)\"\n (pointerdown)=\"pinHover(keyOf(i), $event)\"\n />\n }\n </svg>\n\n @if (tooltip(); as t) {\n <div class=\"mk-chart__tooltip\" [style.left.%]=\"t.left\" [style.top.%]=\"t.top\">\n <span class=\"mk-chart__tooltip-title\">\n <span class=\"mk-chart__swatch\" [style.background]=\"t.color\"></span>\n {{ t.title }}\n </span>\n <span class=\"mk-chart__tooltip-row\">\n <span class=\"mk-chart__tooltip-name\">{{ xLabel() || 'x' }}</span>\n <span class=\"mk-chart__tooltip-value\">{{ t.x }}</span>\n </span>\n <span class=\"mk-chart__tooltip-row\">\n <span class=\"mk-chart__tooltip-name\">{{ yLabel() || 'y' }}</span>\n <span class=\"mk-chart__tooltip-value\">{{ t.y }}</span>\n </span>\n </div>\n }\n</div>\n\n@if (legendVisible()) {\n <ul class=\"mk-chart__legend\">\n @for (item of legend(); track item.name) {\n <li class=\"mk-chart__legend-item\">\n <span class=\"mk-chart__swatch\" [style.background]=\"item.color\"></span>\n {{ item.name }}\n </li>\n }\n </ul>\n}\n\n<table class=\"mk-chart__sr-table\">\n <caption>{{ resolvedLabel() }}</caption>\n <thead>\n <tr>\n <th scope=\"col\">{{ i18n.chartSeries }}</th>\n <th scope=\"col\">{{ xLabel() || 'x' }}</th>\n <th scope=\"col\">{{ yLabel() || 'y' }}</th>\n </tr>\n </thead>\n <tbody>\n @for (s of series(); track s.name) {\n @for (p of s.points; track $index) {\n <tr>\n <th scope=\"row\">{{ s.name }}</th>\n <td>{{ p.x }}</td>\n <td>{{ p.y }}</td>\n </tr>\n }\n }\n </tbody>\n</table>\n", styles: ["@charset \"UTF-8\";:host{display:block;font-family:var(--mk-font-sans);color:var(--mk-text)}.mk-chart__frame{position:relative}.mk-chart__svg{display:block;width:100%;height:auto;overflow:visible}.mk-chart__grid{stroke:var(--mk-chart-grid);stroke-width:1;vector-effect:non-scaling-stroke}.mk-chart__axis-label{fill:var(--mk-chart-axis);font-size:11px}.mk-chart__axis-label--y{text-anchor:end;dominant-baseline:middle}.mk-chart__axis-label--x{text-anchor:middle;dominant-baseline:hanging}.mk-chart__axis-label--tilted{text-anchor:end;dominant-baseline:middle}.mk-chart__bar{transition:opacity var(--mk-duration-fast) var(--mk-ease-standard),filter var(--mk-duration-fast) var(--mk-ease-standard)}.mk-chart__bar:hover{filter:brightness(1.08)}.mk-chart__bar--dim{opacity:.4}.mk-chart__area{stroke:none;opacity:.14}.mk-chart__line{fill:none;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;vector-effect:non-scaling-stroke}.mk-chart__dot{stroke:var(--mk-surface);stroke-width:1.5;vector-effect:non-scaling-stroke}.mk-chart__crosshair{stroke:var(--mk-chart-axis);stroke-width:1;stroke-dasharray:3 3;vector-effect:non-scaling-stroke;opacity:.6}.mk-chart__point{fill-opacity:.72;stroke:var(--mk-surface);stroke-width:1;vector-effect:non-scaling-stroke;cursor:pointer;transition:fill-opacity var(--mk-duration-fast) var(--mk-ease-standard)}.mk-chart__point:hover,.mk-chart__point--active{fill-opacity:1}.mk-radar__ring{fill:none}.mk-radar__area{fill-opacity:.16;stroke-width:2;stroke-linejoin:round;vector-effect:non-scaling-stroke}.mk-radar__axis-label{dominant-baseline:middle}.mk-chart__axis-title{fill:var(--mk-chart-axis);font-size:11px;font-weight:var(--mk-font-weight-medium)}.mk-chart__axis-title--x,.mk-chart__axis-title--y{text-anchor:middle}.mk-chart__slice{stroke:var(--mk-surface);stroke-width:2;transition:opacity var(--mk-duration-fast) var(--mk-ease-standard)}.mk-chart__slice--dim{opacity:.45}.mk-chart__tooltip{position:absolute;z-index:1;transform:translate(-50%,calc(-100% - 8px));pointer-events:none;display:flex;flex-direction:column;gap:2px;padding:var(--mk-space-2) var(--mk-space-3);background-color:var(--mk-surface);color:var(--mk-text);border:var(--mk-border-width) solid var(--mk-border);border-radius:var(--mk-radius-md);box-shadow:var(--mk-shadow-lg);font-size:var(--mk-font-size-sm);white-space:nowrap}.mk-chart__tooltip-title{font-weight:var(--mk-font-weight-semibold)}.mk-chart__tooltip-row{display:flex;align-items:center;gap:var(--mk-space-2)}.mk-chart__tooltip-name{color:var(--mk-text-muted)}.mk-chart__tooltip-value{margin-inline-start:auto;font-variant-numeric:tabular-nums;font-weight:var(--mk-font-weight-medium)}.mk-chart__swatch{flex:none;width:.75rem;height:.75rem;border-radius:var(--mk-radius-xs)}.mk-chart__legend{display:flex;flex-wrap:wrap;gap:var(--mk-space-2) var(--mk-space-4);margin:var(--mk-space-3) 0 0;padding:0;padding-inline-start:var(--mk-space-2);list-style:none}.mk-chart__legend-item{display:inline-flex;align-items:center;gap:var(--mk-space-2);font-size:var(--mk-font-size-sm);color:var(--mk-text-muted)}.mk-donut__frame{margin:0 auto}.mk-donut__center{position:absolute;inset:0;display:flex;flex-direction:column;align-items:center;justify-content:center;gap:2px;pointer-events:none;text-align:center}.mk-donut__center-label{font-size:var(--mk-font-size-2xl);font-weight:var(--mk-font-weight-bold);line-height:1;color:var(--mk-text);font-variant-numeric:tabular-nums}.mk-donut__center-sublabel{font-size:var(--mk-font-size-xs);color:var(--mk-text-subtle);text-transform:uppercase;letter-spacing:.04em}.mk-donut__legend{flex-direction:column;gap:var(--mk-space-2)}.mk-donut__legend .mk-chart__legend-item{width:100%}.mk-donut__legend-name{color:var(--mk-text)}.mk-donut__legend-value{margin-inline-start:auto;color:var(--mk-text-muted);font-variant-numeric:tabular-nums}.mk-chart__sr-table{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border:0}@media(prefers-reduced-motion:reduce){.mk-chart__bar,.mk-chart__slice{transition:none}}.mk-chart__slice--interactive,.mk-chart__bar--interactive,.mk-chart__band--interactive,.mk-chart__legend-item--interactive{cursor:pointer}.mk-chart__slice--interactive:focus-visible,.mk-chart__bar--interactive:focus-visible,.mk-chart__band--interactive:focus-visible{outline:2px solid var(--mk-primary);outline-offset:2px}.mk-chart__legend-button{display:inline-flex;align-items:center;gap:inherit;padding:0;margin:0;border:0;background:transparent;color:inherit;font:inherit;cursor:pointer;border-radius:var(--mk-radius-sm)}.mk-chart__legend-button:focus-visible{outline:2px solid var(--mk-primary);outline-offset:2px}\n"] }]
2223
2840
  }], propDecorators: { series: [{ type: i0.Input, args: [{ isSignal: true, alias: "series", required: false }] }], width: [{ type: i0.Input, args: [{ isSignal: true, alias: "width", required: false }] }], height: [{ type: i0.Input, args: [{ isSignal: true, alias: "height", required: false }] }], pointRadius: [{ type: i0.Input, args: [{ isSignal: true, alias: "pointRadius", required: false }] }], bubble: [{ type: i0.Input, args: [{ isSignal: true, alias: "bubble", required: false }] }], maxRadius: [{ type: i0.Input, args: [{ isSignal: true, alias: "maxRadius", required: false }] }], showGrid: [{ type: i0.Input, args: [{ isSignal: true, alias: "showGrid", required: false }] }], showLegend: [{ type: i0.Input, args: [{ isSignal: true, alias: "showLegend", required: false }] }], xLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "xLabel", required: false }] }], yLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "yLabel", required: false }] }], label: [{ type: i0.Input, args: [{ isSignal: true, alias: "label", required: false }] }] } });
2224
2841
 
2842
+ /** WCAG AA minimum contrast for normal text — what cell values are held to. */
2843
+ const MK_HEATMAP_MIN_CONTRAST = 4.5;
2844
+ /** WCAG 2.x relative luminance of an sRGB colour. */
2845
+ function mkRelativeLuminance([r, g, b]) {
2846
+ const lin = (c) => {
2847
+ const s = c / 255;
2848
+ return s <= 0.04045 ? s / 12.92 : ((s + 0.055) / 1.055) ** 2.4;
2849
+ };
2850
+ return 0.2126 * lin(r) + 0.7152 * lin(g) + 0.0722 * lin(b);
2851
+ }
2852
+ /** WCAG 2.x contrast ratio (1–21) between two colours. */
2853
+ function mkContrastRatio(a, b) {
2854
+ const la = mkRelativeLuminance(a);
2855
+ const lb = mkRelativeLuminance(b);
2856
+ const [hi, lo] = la > lb ? [la, lb] : [lb, la];
2857
+ return (hi + 0.05) / (lo + 0.05);
2858
+ }
2859
+ /** What `color-mix(in srgb, a t%, b)` yields: a linear blend in gamma-encoded sRGB. */
2860
+ function mkMixRgb(a, b, t) {
2861
+ const mix = (x, y) => Math.round(x * t + y * (1 - t));
2862
+ return [mix(a[0], b[0]), mix(a[1], b[1]), mix(a[2], b[2])];
2863
+ }
2864
+ /**
2865
+ * Parse a CSS colour as the CSSOM serialises it — `rgb(r, g, b)` /
2866
+ * `rgba(r, g, b, a)` — or a `#rgb` / `#rrggbb` literal. `null` for anything
2867
+ * else (an unresolved `var()`, `color(...)`, …).
2868
+ */
2869
+ function mkParseRgb(text) {
2870
+ const s = (text ?? '').trim();
2871
+ const fn = /^rgba?\(\s*(\d+(?:\.\d+)?)[\s,]+(\d+(?:\.\d+)?)[\s,]+(\d+(?:\.\d+)?)/i.exec(s);
2872
+ if (fn)
2873
+ return [Number(fn[1]), Number(fn[2]), Number(fn[3])];
2874
+ const hex = /^#([0-9a-f]{3}|[0-9a-f]{6})$/i.exec(s);
2875
+ if (!hex)
2876
+ return null;
2877
+ const h = hex[1].length === 3 ? [...hex[1]].map((c) => c + c).join('') : hex[1];
2878
+ return [parseInt(h.slice(0, 2), 16), parseInt(h.slice(2, 4), 16), parseInt(h.slice(4, 6), 16)];
2879
+ }
2880
+ /** Best of the two text tokens against the cell painted at intensity `t`. */
2881
+ function pickText(t, palette) {
2882
+ const bg = mkMixRgb(palette.accent, palette.surface, t);
2883
+ const onText = mkContrastRatio(palette.text, bg);
2884
+ const onInverse = mkContrastRatio(palette.textInverse, bg);
2885
+ return onInverse > onText
2886
+ ? { intensity: t, inverse: true, contrast: onInverse }
2887
+ : { intensity: t, inverse: false, contrast: onText };
2888
+ }
2889
+ /**
2890
+ * Choose the text token for a cell at intensity `t` (0–1) — light text on
2891
+ * dark cells, dark text on light cells, decided by contrast against the
2892
+ * actual blend rather than a fixed threshold.
2893
+ *
2894
+ * Every accent ramp has a crossover band where neither `--mk-text` nor
2895
+ * `--mk-text-inverse` reaches 4.5:1 (the cell is mid-luminance). When values
2896
+ * are printed in the cells, a cell in that band is painted at the nearest
2897
+ * intensity just outside it, so its value stays readable; the shift is a few
2898
+ * percent of the ramp and the cell keeps its order relative to its
2899
+ * neighbours. Without a resolved palette (server rendering, tests) a plain
2900
+ * threshold is used.
2901
+ */
2902
+ function mkHeatmapCellColors(t, palette, showValues) {
2903
+ const clamped = Math.max(0, Math.min(1, t));
2904
+ if (!palette)
2905
+ return { intensity: clamped, inverse: clamped >= 0.55, contrast: NaN };
2906
+ const best = pickText(clamped, palette);
2907
+ if (!showValues || best.contrast >= MK_HEATMAP_MIN_CONTRAST)
2908
+ return best;
2909
+ // In the crossover band: step outward (down and up alternately, 1 % at a
2910
+ // time) to the closest intensity at which one of the tokens passes.
2911
+ for (let step = 1; step <= 100; step++) {
2912
+ const delta = step / 100;
2913
+ for (const candidate of [clamped - delta, clamped + delta]) {
2914
+ if (candidate < 0 || candidate > 1)
2915
+ continue;
2916
+ const pick = pickText(candidate, palette);
2917
+ if (pick.contrast >= MK_HEATMAP_MIN_CONTRAST)
2918
+ return pick;
2919
+ }
2920
+ }
2921
+ return best;
2922
+ }
2225
2923
  /**
2226
2924
  * Heatmap — a matrix of cells shaded by value intensity, for correlation
2227
2925
  * grids, activity-by-time tables and the like. Rendered as a semantic
2228
2926
  * `<table>` (so it is inherently screen-reader friendly) with cell colours
2229
2927
  * mixed from `accent` over the surface via `color-mix`, so it tracks the theme.
2230
2928
  *
2929
+ * Printed values (`showValues`) pick `--mk-text` or `--mk-text-inverse` per
2930
+ * cell by contrast against that cell's actual colour, in both themes — see
2931
+ * {@link mkHeatmapCellColors}.
2932
+ *
2231
2933
  * ```html
2232
2934
  * <mk-heatmap
2233
2935
  * [xLabels]="hours" [yLabels]="days" [data]="matrix()" showValues />
2234
2936
  * ```
2235
2937
  */
2236
2938
  class MkHeatmap {
2939
+ doc = inject(DOCUMENT$1);
2940
+ host = inject(ElementRef).nativeElement;
2237
2941
  /** Column labels (x axis). */
2238
2942
  xLabels = input([], /* @ts-ignore */
2239
2943
  ...(ngDevMode ? [{ debugName: "xLabels" }] : /* istanbul ignore next */ []));
@@ -2262,6 +2966,25 @@ class MkHeatmap {
2262
2966
  /** Accessible summary; generated from the data when omitted. */
2263
2967
  label = input('', /* @ts-ignore */
2264
2968
  ...(ngDevMode ? [{ debugName: "label" }] : /* istanbul ignore next */ []));
2969
+ /**
2970
+ * The accent and the text/surface tokens resolved through the CSSOM, so
2971
+ * each cell can pick a text colour that actually contrasts with its blend.
2972
+ * `null` until resolved (server, jsdom) — the cells then fall back to a
2973
+ * threshold.
2974
+ */
2975
+ palette = signal(null, /* @ts-ignore */
2976
+ ...(ngDevMode ? [{ debugName: "palette" }] : /* istanbul ignore next */ []));
2977
+ /** Bumped when the document theme changes so the palette is re-resolved. */
2978
+ themeTick = signal(0, /* @ts-ignore */
2979
+ ...(ngDevMode ? [{ debugName: "themeTick" }] : /* istanbul ignore next */ []));
2980
+ constructor() {
2981
+ afterRenderEffect(() => {
2982
+ this.accent();
2983
+ this.themeTick();
2984
+ untracked(() => this.palette.set(this.resolvePalette()));
2985
+ });
2986
+ this.watchTheme();
2987
+ }
2265
2988
  domain = computed(() => {
2266
2989
  const flat = this.data()
2267
2990
  .flat()
@@ -2277,26 +3000,32 @@ class MkHeatmap {
2277
3000
  const span = hi - lo || 1;
2278
3001
  return Math.max(0, Math.min(1, (value - lo) / span));
2279
3002
  }
3003
+ /** The `color-mix()` expression painting a cell at intensity `t`. */
3004
+ cellBackground(t) {
3005
+ return `color-mix(in srgb, ${this.accent()} ${Math.round(t * 100)}%, var(--mk-surface-2))`;
3006
+ }
2280
3007
  rows = computed(() => {
2281
3008
  const xs = this.xLabels();
2282
3009
  const ys = this.yLabels();
2283
3010
  const data = this.data();
2284
3011
  const fmt = this.format();
3012
+ const palette = this.palette();
3013
+ const showValues = this.showValues();
2285
3014
  return ys.map((yLabel, r) => ({
2286
3015
  label: yLabel,
2287
3016
  cells: xs.map((xLabel, c) => {
2288
3017
  const value = data[r]?.[c] ?? null;
2289
3018
  if (value == null) {
2290
- return { value: null, display: '', xLabel, bg: 'transparent', strong: false };
3019
+ return { value: null, display: '', xLabel, bg: 'transparent', inverse: false };
2291
3020
  }
2292
- const t = this.ratio(value);
3021
+ const colors = mkHeatmapCellColors(this.ratio(value), palette, showValues);
2293
3022
  return {
2294
3023
  value,
2295
3024
  display: fmt(value),
2296
3025
  xLabel,
2297
3026
  // Mix the accent over the surface; more intense = more accent.
2298
- bg: `color-mix(in srgb, ${this.accent()} ${Math.round(t * 100)}%, var(--mk-surface-2))`,
2299
- strong: t >= 0.55,
3027
+ bg: this.cellBackground(colors.intensity),
3028
+ inverse: colors.inverse,
2300
3029
  };
2301
3030
  }),
2302
3031
  }));
@@ -2309,7 +3038,7 @@ class MkHeatmap {
2309
3038
  return {
2310
3039
  min: fmt(lo),
2311
3040
  max: fmt(hi),
2312
- swatches: [0, 0.25, 0.5, 0.75, 1].map((t) => `color-mix(in srgb, ${this.accent()} ${t * 100}%, var(--mk-surface-2))`),
3041
+ swatches: [0, 0.25, 0.5, 0.75, 1].map((t) => this.cellBackground(t)),
2313
3042
  };
2314
3043
  }, /* @ts-ignore */
2315
3044
  ...(ngDevMode ? [{ debugName: "scaleStops" }] : /* istanbul ignore next */ []));
@@ -2321,8 +3050,62 @@ class MkHeatmap {
2321
3050
  return `Heatmap, ${rows} rows by ${cols} columns`;
2322
3051
  }, /* @ts-ignore */
2323
3052
  ...(ngDevMode ? [{ debugName: "resolvedLabel" }] : /* istanbul ignore next */ []));
3053
+ /**
3054
+ * Resolve the accent and the tokens to sRGB through a hidden probe: the
3055
+ * probe's computed `color` is what the browser would paint, `var()`s and
3056
+ * `color-mix()` included. `null` when the environment cannot resolve them.
3057
+ */
3058
+ resolvePalette() {
3059
+ const win = this.doc.defaultView;
3060
+ if (!win?.getComputedStyle)
3061
+ return null;
3062
+ const probe = this.doc.createElement('span');
3063
+ probe.setAttribute('aria-hidden', 'true');
3064
+ probe.style.position = 'absolute';
3065
+ probe.style.visibility = 'hidden';
3066
+ this.host.appendChild(probe);
3067
+ try {
3068
+ const read = (expr) => {
3069
+ probe.style.color = '';
3070
+ probe.style.color = expr;
3071
+ return mkParseRgb(win.getComputedStyle(probe).color);
3072
+ };
3073
+ const accent = read(this.accent());
3074
+ const surface = read('var(--mk-surface-2)');
3075
+ const text = read('var(--mk-text)');
3076
+ const textInverse = read('var(--mk-text-inverse)');
3077
+ return accent && surface && text && textInverse
3078
+ ? { accent, surface, text, textInverse }
3079
+ : null;
3080
+ }
3081
+ finally {
3082
+ probe.remove();
3083
+ }
3084
+ }
3085
+ /**
3086
+ * Re-resolve when the theme flips: `data-theme` / class changes on the root
3087
+ * element (MkThemeService and most hand-rolled toggles) and the OS scheme.
3088
+ */
3089
+ watchTheme() {
3090
+ const win = this.doc.defaultView;
3091
+ const root = this.doc.documentElement;
3092
+ if (!win || !root)
3093
+ return;
3094
+ const bump = () => this.themeTick.update((n) => n + 1);
3095
+ const destroyRef = inject(DestroyRef);
3096
+ if (typeof win.MutationObserver === 'function') {
3097
+ const observer = new win.MutationObserver(bump);
3098
+ observer.observe(root, { attributes: true, attributeFilter: ['data-theme', 'class', 'style'] });
3099
+ destroyRef.onDestroy(() => observer.disconnect());
3100
+ }
3101
+ const mql = win.matchMedia?.('(prefers-color-scheme: dark)');
3102
+ if (mql?.addEventListener) {
3103
+ mql.addEventListener('change', bump);
3104
+ destroyRef.onDestroy(() => mql.removeEventListener('change', bump));
3105
+ }
3106
+ }
2324
3107
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.7", ngImport: i0, type: MkHeatmap, deps: [], target: i0.ɵɵFactoryTarget.Component });
2325
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.0.7", type: MkHeatmap, isStandalone: true, selector: "mk-heatmap", inputs: { xLabels: { classPropertyName: "xLabels", publicName: "xLabels", isSignal: true, isRequired: false, transformFunction: null }, yLabels: { classPropertyName: "yLabels", publicName: "yLabels", isSignal: true, isRequired: false, transformFunction: null }, data: { classPropertyName: "data", publicName: "data", isSignal: true, isRequired: false, transformFunction: null }, min: { classPropertyName: "min", publicName: "min", isSignal: true, isRequired: false, transformFunction: null }, max: { classPropertyName: "max", publicName: "max", isSignal: true, isRequired: false, transformFunction: null }, accent: { classPropertyName: "accent", publicName: "accent", isSignal: true, isRequired: false, transformFunction: null }, showValues: { classPropertyName: "showValues", publicName: "showValues", isSignal: true, isRequired: false, transformFunction: null }, showScale: { classPropertyName: "showScale", publicName: "showScale", isSignal: true, isRequired: false, transformFunction: null }, format: { classPropertyName: "format", publicName: "format", isSignal: true, isRequired: false, transformFunction: null }, label: { classPropertyName: "label", publicName: "label", isSignal: true, isRequired: false, transformFunction: null } }, host: { attributes: { "role": "group" }, properties: { "attr.aria-label": "resolvedLabel()" }, classAttribute: "mk-chart mk-heatmap" }, ngImport: i0, template: "<!-- Focusable so keyboard users can scroll the overflowing grid (WCAG 2.1.1). -->\n<div\n class=\"mk-chart__frame mk-heatmap__scroll\"\n role=\"region\"\n tabindex=\"0\"\n [attr.aria-label]=\"resolvedLabel()\"\n>\n <table class=\"mk-heatmap__grid\">\n <caption class=\"mk-visually-hidden\">{{ resolvedLabel() }}</caption>\n <thead>\n <tr>\n <td class=\"mk-heatmap__corner\"></td>\n @for (x of xLabels(); track $index) {\n <th scope=\"col\" class=\"mk-heatmap__col-head\">{{ x }}</th>\n }\n </tr>\n </thead>\n <tbody>\n @for (row of rows(); track row.label) {\n <tr>\n <th scope=\"row\" class=\"mk-heatmap__row-head\">{{ row.label }}</th>\n @for (cell of row.cells; track $index) {\n <td\n class=\"mk-heatmap__cell\"\n [class.mk-heatmap__cell--strong]=\"cell.strong\"\n [class.mk-heatmap__cell--empty]=\"cell.value === null\"\n [style.background]=\"cell.bg\"\n [attr.title]=\"\n cell.value === null\n ? null\n : row.label + ' \u00B7 ' + cell.xLabel + ': ' + cell.display\n \"\n >\n @if (cell.value !== null) {\n @if (showValues()) {\n <span class=\"mk-heatmap__value\">{{ cell.display }}</span>\n } @else {\n <!-- Colour must not be the only signal: expose the value to AT. -->\n <span class=\"mk-visually-hidden\">{{ cell.display }}</span>\n }\n }\n </td>\n }\n </tr>\n }\n </tbody>\n </table>\n</div>\n\n@if (showScale()) {\n <div class=\"mk-heatmap__legend\" aria-hidden=\"true\">\n <span class=\"mk-heatmap__legend-label\">{{ scaleStops().min }}</span>\n <span class=\"mk-heatmap__legend-ramp\">\n @for (sw of scaleStops().swatches; track $index) {\n <span class=\"mk-heatmap__legend-swatch\" [style.background]=\"sw\"></span>\n }\n </span>\n <span class=\"mk-heatmap__legend-label\">{{ scaleStops().max }}</span>\n </div>\n}\n", styles: [":host{display:block;font-family:var(--mk-font-sans)}.mk-heatmap__scroll{width:100%;overflow-x:auto}.mk-heatmap__scroll:focus-visible{outline:var(--mk-focus-ring-width) solid var(--mk-focus-ring);outline-offset:calc(-1 * var(--mk-focus-ring-width))}.mk-heatmap__grid{border-collapse:separate;border-spacing:3px;font-size:var(--mk-font-size-sm);color:var(--mk-text)}.mk-heatmap__corner{border:0}.mk-heatmap__col-head,.mk-heatmap__row-head{padding:var(--mk-space-1) var(--mk-space-2);font-weight:var(--mk-font-weight-medium);color:var(--mk-text-muted);white-space:nowrap}.mk-heatmap__col-head{text-align:center;vertical-align:bottom}.mk-heatmap__row-head{text-align:end}.mk-heatmap__cell{width:2.25rem;height:2.25rem;padding:0;text-align:center;vertical-align:middle;border-radius:var(--mk-radius-sm);color:var(--mk-text-muted);transition:outline-color var(--mk-duration-fast) var(--mk-ease-standard);outline:2px solid transparent;outline-offset:-2px}.mk-heatmap__cell:hover{outline-color:var(--mk-border-strong)}.mk-heatmap__cell--strong{color:var(--mk-primary-contrast)}.mk-heatmap__cell--empty{outline:none}.mk-heatmap__cell--empty:hover{outline-color:transparent}.mk-heatmap__value{font-size:var(--mk-font-size-xs);font-variant-numeric:tabular-nums}.mk-heatmap__legend{display:flex;align-items:center;gap:var(--mk-space-2);margin-top:var(--mk-space-3);font-size:var(--mk-font-size-xs);color:var(--mk-text-muted)}.mk-heatmap__legend-ramp{display:inline-flex;gap:2px}.mk-heatmap__legend-swatch{width:1.1rem;height:.75rem;border-radius:2px}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush });
3108
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.0.7", type: MkHeatmap, isStandalone: true, selector: "mk-heatmap", inputs: { xLabels: { classPropertyName: "xLabels", publicName: "xLabels", isSignal: true, isRequired: false, transformFunction: null }, yLabels: { classPropertyName: "yLabels", publicName: "yLabels", isSignal: true, isRequired: false, transformFunction: null }, data: { classPropertyName: "data", publicName: "data", isSignal: true, isRequired: false, transformFunction: null }, min: { classPropertyName: "min", publicName: "min", isSignal: true, isRequired: false, transformFunction: null }, max: { classPropertyName: "max", publicName: "max", isSignal: true, isRequired: false, transformFunction: null }, accent: { classPropertyName: "accent", publicName: "accent", isSignal: true, isRequired: false, transformFunction: null }, showValues: { classPropertyName: "showValues", publicName: "showValues", isSignal: true, isRequired: false, transformFunction: null }, showScale: { classPropertyName: "showScale", publicName: "showScale", isSignal: true, isRequired: false, transformFunction: null }, format: { classPropertyName: "format", publicName: "format", isSignal: true, isRequired: false, transformFunction: null }, label: { classPropertyName: "label", publicName: "label", isSignal: true, isRequired: false, transformFunction: null } }, host: { attributes: { "role": "group" }, properties: { "attr.aria-label": "resolvedLabel()" }, classAttribute: "mk-chart mk-heatmap" }, ngImport: i0, template: "<!-- Focusable so keyboard users can scroll the overflowing grid (WCAG 2.1.1). -->\n<div\n class=\"mk-chart__frame mk-heatmap__scroll\"\n role=\"region\"\n tabindex=\"0\"\n [attr.aria-label]=\"resolvedLabel()\"\n>\n <table class=\"mk-heatmap__grid\">\n <caption class=\"mk-visually-hidden\">{{ resolvedLabel() }}</caption>\n <thead>\n <tr>\n <td class=\"mk-heatmap__corner\"></td>\n @for (x of xLabels(); track $index) {\n <th scope=\"col\" class=\"mk-heatmap__col-head\">{{ x }}</th>\n }\n </tr>\n </thead>\n <tbody>\n @for (row of rows(); track row.label) {\n <tr>\n <th scope=\"row\" class=\"mk-heatmap__row-head\">{{ row.label }}</th>\n @for (cell of row.cells; track $index) {\n <td\n class=\"mk-heatmap__cell\"\n [class.mk-heatmap__cell--inverse]=\"cell.inverse\"\n [class.mk-heatmap__cell--empty]=\"cell.value === null\"\n [style.background]=\"cell.bg\"\n [attr.title]=\"\n cell.value === null\n ? null\n : row.label + ' \u00B7 ' + cell.xLabel + ': ' + cell.display\n \"\n >\n @if (cell.value !== null) {\n @if (showValues()) {\n <span class=\"mk-heatmap__value\">{{ cell.display }}</span>\n } @else {\n <!-- Colour must not be the only signal: expose the value to AT. -->\n <span class=\"mk-visually-hidden\">{{ cell.display }}</span>\n }\n }\n </td>\n }\n </tr>\n }\n </tbody>\n </table>\n</div>\n\n@if (showScale()) {\n <div class=\"mk-heatmap__legend\" aria-hidden=\"true\">\n <span class=\"mk-heatmap__legend-label\">{{ scaleStops().min }}</span>\n <span class=\"mk-heatmap__legend-ramp\">\n @for (sw of scaleStops().swatches; track $index) {\n <span class=\"mk-heatmap__legend-swatch\" [style.background]=\"sw\"></span>\n }\n </span>\n <span class=\"mk-heatmap__legend-label\">{{ scaleStops().max }}</span>\n </div>\n}\n", styles: ["@charset \"UTF-8\";:host{display:block;font-family:var(--mk-font-sans)}.mk-heatmap__scroll{width:100%;overflow-x:auto}.mk-heatmap__scroll:focus-visible{outline:var(--mk-focus-ring-width) solid var(--mk-focus-ring);outline-offset:calc(-1 * var(--mk-focus-ring-width))}.mk-heatmap__grid{border-collapse:separate;border-spacing:3px;font-size:var(--mk-font-size-sm);color:var(--mk-text)}.mk-heatmap__corner{border:0}.mk-heatmap__col-head,.mk-heatmap__row-head{padding:var(--mk-space-1) var(--mk-space-2);font-weight:var(--mk-font-weight-medium);color:var(--mk-text-muted);white-space:nowrap}.mk-heatmap__col-head{text-align:center;vertical-align:bottom}.mk-heatmap__row-head{text-align:end}.mk-heatmap__cell{width:2.25rem;height:2.25rem;padding:0;text-align:center;vertical-align:middle;border-radius:var(--mk-radius-sm);color:var(--mk-text);transition:outline-color var(--mk-duration-fast) var(--mk-ease-standard);outline:2px solid transparent;outline-offset:-2px}.mk-heatmap__cell:hover{outline-color:var(--mk-border-strong)}.mk-heatmap__cell--inverse{color:var(--mk-text-inverse)}.mk-heatmap__cell--empty{outline:none}.mk-heatmap__cell--empty:hover{outline-color:transparent}.mk-heatmap__value{font-size:var(--mk-font-size-xs);font-variant-numeric:tabular-nums}.mk-heatmap__legend{display:flex;align-items:center;gap:var(--mk-space-2);margin-top:var(--mk-space-3);font-size:var(--mk-font-size-xs);color:var(--mk-text-muted)}.mk-heatmap__legend-ramp{display:inline-flex;gap:2px}.mk-heatmap__legend-swatch{width:1.1rem;height:.75rem;border-radius:2px;box-shadow:inset 0 0 0 1px var(--mk-border-subtle)}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush });
2326
3109
  }
2327
3110
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.7", ngImport: i0, type: MkHeatmap, decorators: [{
2328
3111
  type: Component,
@@ -2330,8 +3113,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.7", ngImpor
2330
3113
  class: 'mk-chart mk-heatmap',
2331
3114
  role: 'group',
2332
3115
  '[attr.aria-label]': 'resolvedLabel()',
2333
- }, template: "<!-- Focusable so keyboard users can scroll the overflowing grid (WCAG 2.1.1). -->\n<div\n class=\"mk-chart__frame mk-heatmap__scroll\"\n role=\"region\"\n tabindex=\"0\"\n [attr.aria-label]=\"resolvedLabel()\"\n>\n <table class=\"mk-heatmap__grid\">\n <caption class=\"mk-visually-hidden\">{{ resolvedLabel() }}</caption>\n <thead>\n <tr>\n <td class=\"mk-heatmap__corner\"></td>\n @for (x of xLabels(); track $index) {\n <th scope=\"col\" class=\"mk-heatmap__col-head\">{{ x }}</th>\n }\n </tr>\n </thead>\n <tbody>\n @for (row of rows(); track row.label) {\n <tr>\n <th scope=\"row\" class=\"mk-heatmap__row-head\">{{ row.label }}</th>\n @for (cell of row.cells; track $index) {\n <td\n class=\"mk-heatmap__cell\"\n [class.mk-heatmap__cell--strong]=\"cell.strong\"\n [class.mk-heatmap__cell--empty]=\"cell.value === null\"\n [style.background]=\"cell.bg\"\n [attr.title]=\"\n cell.value === null\n ? null\n : row.label + ' \u00B7 ' + cell.xLabel + ': ' + cell.display\n \"\n >\n @if (cell.value !== null) {\n @if (showValues()) {\n <span class=\"mk-heatmap__value\">{{ cell.display }}</span>\n } @else {\n <!-- Colour must not be the only signal: expose the value to AT. -->\n <span class=\"mk-visually-hidden\">{{ cell.display }}</span>\n }\n }\n </td>\n }\n </tr>\n }\n </tbody>\n </table>\n</div>\n\n@if (showScale()) {\n <div class=\"mk-heatmap__legend\" aria-hidden=\"true\">\n <span class=\"mk-heatmap__legend-label\">{{ scaleStops().min }}</span>\n <span class=\"mk-heatmap__legend-ramp\">\n @for (sw of scaleStops().swatches; track $index) {\n <span class=\"mk-heatmap__legend-swatch\" [style.background]=\"sw\"></span>\n }\n </span>\n <span class=\"mk-heatmap__legend-label\">{{ scaleStops().max }}</span>\n </div>\n}\n", styles: [":host{display:block;font-family:var(--mk-font-sans)}.mk-heatmap__scroll{width:100%;overflow-x:auto}.mk-heatmap__scroll:focus-visible{outline:var(--mk-focus-ring-width) solid var(--mk-focus-ring);outline-offset:calc(-1 * var(--mk-focus-ring-width))}.mk-heatmap__grid{border-collapse:separate;border-spacing:3px;font-size:var(--mk-font-size-sm);color:var(--mk-text)}.mk-heatmap__corner{border:0}.mk-heatmap__col-head,.mk-heatmap__row-head{padding:var(--mk-space-1) var(--mk-space-2);font-weight:var(--mk-font-weight-medium);color:var(--mk-text-muted);white-space:nowrap}.mk-heatmap__col-head{text-align:center;vertical-align:bottom}.mk-heatmap__row-head{text-align:end}.mk-heatmap__cell{width:2.25rem;height:2.25rem;padding:0;text-align:center;vertical-align:middle;border-radius:var(--mk-radius-sm);color:var(--mk-text-muted);transition:outline-color var(--mk-duration-fast) var(--mk-ease-standard);outline:2px solid transparent;outline-offset:-2px}.mk-heatmap__cell:hover{outline-color:var(--mk-border-strong)}.mk-heatmap__cell--strong{color:var(--mk-primary-contrast)}.mk-heatmap__cell--empty{outline:none}.mk-heatmap__cell--empty:hover{outline-color:transparent}.mk-heatmap__value{font-size:var(--mk-font-size-xs);font-variant-numeric:tabular-nums}.mk-heatmap__legend{display:flex;align-items:center;gap:var(--mk-space-2);margin-top:var(--mk-space-3);font-size:var(--mk-font-size-xs);color:var(--mk-text-muted)}.mk-heatmap__legend-ramp{display:inline-flex;gap:2px}.mk-heatmap__legend-swatch{width:1.1rem;height:.75rem;border-radius:2px}\n"] }]
2334
- }], propDecorators: { xLabels: [{ type: i0.Input, args: [{ isSignal: true, alias: "xLabels", required: false }] }], yLabels: [{ type: i0.Input, args: [{ isSignal: true, alias: "yLabels", required: false }] }], data: [{ type: i0.Input, args: [{ isSignal: true, alias: "data", required: false }] }], min: [{ type: i0.Input, args: [{ isSignal: true, alias: "min", required: false }] }], max: [{ type: i0.Input, args: [{ isSignal: true, alias: "max", required: false }] }], accent: [{ type: i0.Input, args: [{ isSignal: true, alias: "accent", required: false }] }], showValues: [{ type: i0.Input, args: [{ isSignal: true, alias: "showValues", required: false }] }], showScale: [{ type: i0.Input, args: [{ isSignal: true, alias: "showScale", required: false }] }], format: [{ type: i0.Input, args: [{ isSignal: true, alias: "format", required: false }] }], label: [{ type: i0.Input, args: [{ isSignal: true, alias: "label", required: false }] }] } });
3116
+ }, template: "<!-- Focusable so keyboard users can scroll the overflowing grid (WCAG 2.1.1). -->\n<div\n class=\"mk-chart__frame mk-heatmap__scroll\"\n role=\"region\"\n tabindex=\"0\"\n [attr.aria-label]=\"resolvedLabel()\"\n>\n <table class=\"mk-heatmap__grid\">\n <caption class=\"mk-visually-hidden\">{{ resolvedLabel() }}</caption>\n <thead>\n <tr>\n <td class=\"mk-heatmap__corner\"></td>\n @for (x of xLabels(); track $index) {\n <th scope=\"col\" class=\"mk-heatmap__col-head\">{{ x }}</th>\n }\n </tr>\n </thead>\n <tbody>\n @for (row of rows(); track row.label) {\n <tr>\n <th scope=\"row\" class=\"mk-heatmap__row-head\">{{ row.label }}</th>\n @for (cell of row.cells; track $index) {\n <td\n class=\"mk-heatmap__cell\"\n [class.mk-heatmap__cell--inverse]=\"cell.inverse\"\n [class.mk-heatmap__cell--empty]=\"cell.value === null\"\n [style.background]=\"cell.bg\"\n [attr.title]=\"\n cell.value === null\n ? null\n : row.label + ' \u00B7 ' + cell.xLabel + ': ' + cell.display\n \"\n >\n @if (cell.value !== null) {\n @if (showValues()) {\n <span class=\"mk-heatmap__value\">{{ cell.display }}</span>\n } @else {\n <!-- Colour must not be the only signal: expose the value to AT. -->\n <span class=\"mk-visually-hidden\">{{ cell.display }}</span>\n }\n }\n </td>\n }\n </tr>\n }\n </tbody>\n </table>\n</div>\n\n@if (showScale()) {\n <div class=\"mk-heatmap__legend\" aria-hidden=\"true\">\n <span class=\"mk-heatmap__legend-label\">{{ scaleStops().min }}</span>\n <span class=\"mk-heatmap__legend-ramp\">\n @for (sw of scaleStops().swatches; track $index) {\n <span class=\"mk-heatmap__legend-swatch\" [style.background]=\"sw\"></span>\n }\n </span>\n <span class=\"mk-heatmap__legend-label\">{{ scaleStops().max }}</span>\n </div>\n}\n", styles: ["@charset \"UTF-8\";:host{display:block;font-family:var(--mk-font-sans)}.mk-heatmap__scroll{width:100%;overflow-x:auto}.mk-heatmap__scroll:focus-visible{outline:var(--mk-focus-ring-width) solid var(--mk-focus-ring);outline-offset:calc(-1 * var(--mk-focus-ring-width))}.mk-heatmap__grid{border-collapse:separate;border-spacing:3px;font-size:var(--mk-font-size-sm);color:var(--mk-text)}.mk-heatmap__corner{border:0}.mk-heatmap__col-head,.mk-heatmap__row-head{padding:var(--mk-space-1) var(--mk-space-2);font-weight:var(--mk-font-weight-medium);color:var(--mk-text-muted);white-space:nowrap}.mk-heatmap__col-head{text-align:center;vertical-align:bottom}.mk-heatmap__row-head{text-align:end}.mk-heatmap__cell{width:2.25rem;height:2.25rem;padding:0;text-align:center;vertical-align:middle;border-radius:var(--mk-radius-sm);color:var(--mk-text);transition:outline-color var(--mk-duration-fast) var(--mk-ease-standard);outline:2px solid transparent;outline-offset:-2px}.mk-heatmap__cell:hover{outline-color:var(--mk-border-strong)}.mk-heatmap__cell--inverse{color:var(--mk-text-inverse)}.mk-heatmap__cell--empty{outline:none}.mk-heatmap__cell--empty:hover{outline-color:transparent}.mk-heatmap__value{font-size:var(--mk-font-size-xs);font-variant-numeric:tabular-nums}.mk-heatmap__legend{display:flex;align-items:center;gap:var(--mk-space-2);margin-top:var(--mk-space-3);font-size:var(--mk-font-size-xs);color:var(--mk-text-muted)}.mk-heatmap__legend-ramp{display:inline-flex;gap:2px}.mk-heatmap__legend-swatch{width:1.1rem;height:.75rem;border-radius:2px;box-shadow:inset 0 0 0 1px var(--mk-border-subtle)}\n"] }]
3117
+ }], ctorParameters: () => [], propDecorators: { xLabels: [{ type: i0.Input, args: [{ isSignal: true, alias: "xLabels", required: false }] }], yLabels: [{ type: i0.Input, args: [{ isSignal: true, alias: "yLabels", required: false }] }], data: [{ type: i0.Input, args: [{ isSignal: true, alias: "data", required: false }] }], min: [{ type: i0.Input, args: [{ isSignal: true, alias: "min", required: false }] }], max: [{ type: i0.Input, args: [{ isSignal: true, alias: "max", required: false }] }], accent: [{ type: i0.Input, args: [{ isSignal: true, alias: "accent", required: false }] }], showValues: [{ type: i0.Input, args: [{ isSignal: true, alias: "showValues", required: false }] }], showScale: [{ type: i0.Input, args: [{ isSignal: true, alias: "showScale", required: false }] }], format: [{ type: i0.Input, args: [{ isSignal: true, alias: "format", required: false }] }], label: [{ type: i0.Input, args: [{ isSignal: true, alias: "label", required: false }] }] } });
2335
3118
 
2336
3119
  /** Local midnight for `d` (drops the time-of-day). */
2337
3120
  function stripTime(d) {
@@ -3135,6 +3918,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.7", ngImpor
3135
3918
  class MkInlineEdit {
3136
3919
  injector = inject(Injector);
3137
3920
  field = inject(MkFieldContext, { optional: true });
3921
+ /** Signal Forms: gates `invalid` until the bound field is touched or dirty. */
3922
+ fieldTouched = mkInjectFieldTouched();
3138
3923
  i18n = inject(MK_I18N);
3139
3924
  displayRef = viewChild('display', /* @ts-ignore */
3140
3925
  ...(ngDevMode ? [{ debugName: "displayRef" }] : /* istanbul ignore next */ []));
@@ -3177,7 +3962,7 @@ class MkInlineEdit {
3177
3962
  ...(ngDevMode ? [{ debugName: "effectiveSize" }] : /* istanbul ignore next */ []));
3178
3963
  isDisabled = computed(() => this.disabled() || this.cvaDisabled(), /* @ts-ignore */
3179
3964
  ...(ngDevMode ? [{ debugName: "isDisabled" }] : /* istanbul ignore next */ []));
3180
- isInvalid = computed(() => this.invalid() || (this.field?.hasError() ?? false), /* @ts-ignore */
3965
+ isInvalid = computed(() => (this.invalid() && this.fieldTouched()) || (this.field?.hasError() ?? false), /* @ts-ignore */
3181
3966
  ...(ngDevMode ? [{ debugName: "isInvalid" }] : /* istanbul ignore next */ []));
3182
3967
  labelledBy = computed(() => this.field?.labelId ?? null, /* @ts-ignore */
3183
3968
  ...(ngDevMode ? [{ debugName: "labelledBy" }] : /* istanbul ignore next */ []));
@@ -3989,11 +4774,11 @@ class MkCarousel {
3989
4774
  this.io = undefined;
3990
4775
  }
3991
4776
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.7", ngImport: i0, type: MkCarousel, deps: [], target: i0.ɵɵFactoryTarget.Component });
3992
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.0.7", type: MkCarousel, isStandalone: true, selector: "mk-carousel", inputs: { index: { classPropertyName: "index", publicName: "index", isSignal: true, isRequired: false, transformFunction: null }, ariaLabel: { classPropertyName: "ariaLabel", publicName: "ariaLabel", isSignal: true, isRequired: false, transformFunction: null }, loop: { classPropertyName: "loop", publicName: "loop", isSignal: true, isRequired: false, transformFunction: null }, showDots: { classPropertyName: "showDots", publicName: "showDots", isSignal: true, isRequired: false, transformFunction: null }, showArrows: { classPropertyName: "showArrows", publicName: "showArrows", isSignal: true, isRequired: false, transformFunction: null }, autoplay: { classPropertyName: "autoplay", publicName: "autoplay", isSignal: true, isRequired: false, transformFunction: null }, interval: { classPropertyName: "interval", publicName: "interval", isSignal: true, isRequired: false, transformFunction: null }, userPaused: { classPropertyName: "userPaused", publicName: "userPaused", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { index: "indexChange", userPaused: "userPausedChange" }, host: { classAttribute: "mk-carousel" }, queries: [{ propertyName: "slides", predicate: MkCarouselSlide, isSignal: true }], ngImport: i0, template: "<div\n class=\"mk-carousel__viewport\"\n role=\"region\"\n aria-roledescription=\"carousel\"\n [attr.aria-label]=\"ariaLabel()\"\n tabindex=\"0\"\n (keydown)=\"onKeydown($event)\"\n (mouseenter)=\"pause()\"\n (mouseleave)=\"resume()\"\n (focusin)=\"pause()\"\n (focusout)=\"resume()\"\n (pointerdown)=\"onPointerDown($event)\"\n (pointermove)=\"onPointerMove($event)\"\n (pointerup)=\"onPointerUp($event)\"\n (pointercancel)=\"onPointerUp($event)\"\n>\n @if (autoplay()) {\n <button\n type=\"button\"\n class=\"mk-carousel__playpause\"\n [attr.aria-label]=\"userPaused() ? i18n.playSlideshow : i18n.pauseSlideshow\"\n [attr.aria-pressed]=\"userPaused()\"\n (click)=\"toggleUserPause()\"\n >\n <span aria-hidden=\"true\">{{ userPaused() ? '\u25B6' : '\u23F8' }}</span>\n </button>\n }\n <div\n class=\"mk-carousel__track\"\n [class.mk-carousel__track--dragging]=\"dragging()\"\n [style.transform]=\"trackTransform()\"\n >\n <ng-content />\n </div>\n\n @if (showArrows() && count() > 1) {\n <button\n type=\"button\"\n class=\"mk-carousel__arrow mk-carousel__arrow--prev\"\n [attr.aria-label]=\"i18n.previousSlide\"\n (click)=\"prev()\"\n >\n <span aria-hidden=\"true\">\u2039</span>\n </button>\n <button\n type=\"button\"\n class=\"mk-carousel__arrow mk-carousel__arrow--next\"\n [attr.aria-label]=\"i18n.nextSlide\"\n (click)=\"next()\"\n >\n <span aria-hidden=\"true\">\u203A</span>\n </button>\n }\n</div>\n\n@if (showDots() && count() > 1) {\n <div class=\"mk-carousel__dots\">\n @for (dot of dots(); track dot) {\n <button\n type=\"button\"\n class=\"mk-carousel__dot\"\n [class.mk-carousel__dot--active]=\"dot === index()\"\n [attr.aria-current]=\"dot === index() || null\"\n [attr.aria-label]=\"i18n.goToSlide(dot + 1)\"\n (click)=\"goTo(dot)\"\n ></button>\n }\n </div>\n}\n\n<div class=\"mk-visually-hidden\" [attr.aria-live]=\"liveMode()\">{{ liveText() }}</div>\n", styles: ["@charset \"UTF-8\";:host{display:block;font-family:var(--mk-font-sans)}.mk-carousel__viewport{position:relative;overflow:hidden;border-radius:var(--mk-radius-md);touch-action:pan-y}.mk-carousel__viewport:focus-visible{outline:var(--mk-focus-ring-width) solid var(--mk-focus-ring);outline-offset:var(--mk-focus-ring-offset)}.mk-carousel__track{display:flex;transition:transform var(--mk-duration-normal, .24s) var(--mk-ease-standard)}.mk-carousel__track--dragging{transition:none}.mk-carousel__slide{flex:0 0 100%;min-width:0}.mk-carousel__playpause{position:absolute;top:var(--mk-space-2);inset-inline-start:var(--mk-space-2);z-index:1;display:grid;place-items:center;width:2rem;height:2rem;padding:0;font-size:var(--mk-font-size-sm);line-height:1;color:var(--mk-text);background-color:var(--mk-surface);border:var(--mk-border-width) solid var(--mk-border);border-radius:var(--mk-radius-circle);box-shadow:var(--mk-shadow-sm);cursor:pointer;transition:background-color var(--mk-duration-fast) var(--mk-ease-standard)}.mk-carousel__playpause:hover{background-color:var(--mk-surface-2)}.mk-carousel__playpause:focus-visible{outline:var(--mk-focus-ring-width) solid var(--mk-focus-ring);outline-offset:var(--mk-focus-ring-offset)}.mk-carousel__arrow{position:absolute;top:50%;transform:translateY(-50%);display:grid;place-items:center;width:2rem;height:2rem;font-size:var(--mk-font-size-lg);line-height:1;color:var(--mk-text);background-color:var(--mk-surface);border:var(--mk-border-width) solid var(--mk-border);border-radius:var(--mk-radius-circle);box-shadow:var(--mk-shadow-sm);cursor:pointer;transition:background-color var(--mk-duration-fast) var(--mk-ease-standard)}.mk-carousel__arrow:hover{background-color:var(--mk-surface-2)}.mk-carousel__arrow:focus-visible{outline:var(--mk-focus-ring-width) solid var(--mk-focus-ring);outline-offset:var(--mk-focus-ring-offset)}.mk-carousel__arrow--prev{inset-inline-start:var(--mk-space-2)}.mk-carousel__arrow--next{inset-inline-end:var(--mk-space-2)}.mk-carousel__arrow:dir(rtl) span{display:inline-block;transform:scaleX(-1)}.mk-carousel__dots{display:flex;justify-content:center;gap:var(--mk-space-2);margin-top:var(--mk-space-2)}.mk-carousel__dot{width:.5rem;height:.5rem;padding:0;background-color:var(--mk-border-strong);border:none;border-radius:var(--mk-radius-circle);cursor:pointer;transition:background-color var(--mk-duration-fast) var(--mk-ease-standard),transform var(--mk-duration-fast) var(--mk-ease-standard)}.mk-carousel__dot:hover{background-color:var(--mk-text-muted)}.mk-carousel__dot:focus-visible{outline:var(--mk-focus-ring-width) solid var(--mk-focus-ring);outline-offset:var(--mk-focus-ring-offset)}.mk-carousel__dot--active{background-color:var(--mk-primary);transform:scale(1.25)}@media(prefers-reduced-motion:reduce){.mk-carousel__track,.mk-carousel__arrow,.mk-carousel__dot{transition:none}}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush });
4777
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.0.7", type: MkCarousel, isStandalone: true, selector: "mk-carousel", inputs: { index: { classPropertyName: "index", publicName: "index", isSignal: true, isRequired: false, transformFunction: null }, ariaLabel: { classPropertyName: "ariaLabel", publicName: "ariaLabel", isSignal: true, isRequired: false, transformFunction: null }, loop: { classPropertyName: "loop", publicName: "loop", isSignal: true, isRequired: false, transformFunction: null }, showDots: { classPropertyName: "showDots", publicName: "showDots", isSignal: true, isRequired: false, transformFunction: null }, showArrows: { classPropertyName: "showArrows", publicName: "showArrows", isSignal: true, isRequired: false, transformFunction: null }, autoplay: { classPropertyName: "autoplay", publicName: "autoplay", isSignal: true, isRequired: false, transformFunction: null }, interval: { classPropertyName: "interval", publicName: "interval", isSignal: true, isRequired: false, transformFunction: null }, userPaused: { classPropertyName: "userPaused", publicName: "userPaused", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { index: "indexChange", userPaused: "userPausedChange" }, host: { classAttribute: "mk-carousel" }, queries: [{ propertyName: "slides", predicate: MkCarouselSlide, isSignal: true }], ngImport: i0, template: "<div\n class=\"mk-carousel__viewport\"\n role=\"region\"\n aria-roledescription=\"carousel\"\n [attr.aria-label]=\"ariaLabel()\"\n tabindex=\"0\"\n (keydown)=\"onKeydown($event)\"\n (mouseenter)=\"pause()\"\n (mouseleave)=\"resume()\"\n (focusin)=\"pause()\"\n (focusout)=\"resume()\"\n (pointerdown)=\"onPointerDown($event)\"\n (pointermove)=\"onPointerMove($event)\"\n (pointerup)=\"onPointerUp($event)\"\n (pointercancel)=\"onPointerUp($event)\"\n>\n @if (autoplay()) {\n <button\n type=\"button\"\n class=\"mk-carousel__playpause\"\n [attr.aria-label]=\"userPaused() ? i18n.playSlideshow : i18n.pauseSlideshow\"\n [attr.aria-pressed]=\"userPaused()\"\n (click)=\"toggleUserPause()\"\n >\n <span aria-hidden=\"true\">{{ userPaused() ? '\u25B6' : '\u23F8' }}</span>\n </button>\n }\n <div\n class=\"mk-carousel__track\"\n [class.mk-carousel__track--dragging]=\"dragging()\"\n [style.transform]=\"trackTransform()\"\n >\n <ng-content />\n </div>\n\n @if (showArrows() && count() > 1) {\n <button\n type=\"button\"\n class=\"mk-carousel__arrow mk-carousel__arrow--prev\"\n [attr.aria-label]=\"i18n.previousSlide\"\n (click)=\"prev()\"\n >\n <span aria-hidden=\"true\">\u2039</span>\n </button>\n <button\n type=\"button\"\n class=\"mk-carousel__arrow mk-carousel__arrow--next\"\n [attr.aria-label]=\"i18n.nextSlide\"\n (click)=\"next()\"\n >\n <span aria-hidden=\"true\">\u203A</span>\n </button>\n }\n</div>\n\n@if (showDots() && count() > 1) {\n <div class=\"mk-carousel__dots\">\n @for (dot of dots(); track dot) {\n <button\n type=\"button\"\n class=\"mk-carousel__dot\"\n [class.mk-carousel__dot--active]=\"dot === index()\"\n [attr.aria-current]=\"dot === index() || null\"\n [attr.aria-label]=\"i18n.goToSlide(dot + 1)\"\n (click)=\"goTo(dot)\"\n ></button>\n }\n </div>\n}\n\n<div class=\"mk-visually-hidden\" [attr.aria-live]=\"liveMode()\">{{ liveText() }}</div>\n", styles: ["@charset \"UTF-8\";:host{display:block;font-family:var(--mk-font-sans)}.mk-carousel__viewport{position:relative;overflow:hidden;border-radius:var(--mk-radius-md);touch-action:pan-y}.mk-carousel__viewport:focus-visible{outline:var(--mk-focus-ring-width) solid var(--mk-focus-ring);outline-offset:var(--mk-focus-ring-offset)}.mk-carousel__track{display:flex;transition:transform var(--mk-duration-normal, .24s) var(--mk-ease-standard)}.mk-carousel__track--dragging{transition:none}:host ::ng-deep .mk-carousel__slide{flex:0 0 100%;min-width:0;box-sizing:border-box}.mk-carousel__playpause{position:absolute;top:var(--mk-space-2);inset-inline-start:var(--mk-space-2);z-index:1;display:grid;place-items:center;width:2rem;height:2rem;padding:0;font-size:var(--mk-font-size-sm);line-height:1;color:var(--mk-text);background-color:var(--mk-surface);border:var(--mk-border-width) solid var(--mk-border);border-radius:var(--mk-radius-circle);box-shadow:var(--mk-shadow-sm);cursor:pointer;transition:background-color var(--mk-duration-fast) var(--mk-ease-standard)}.mk-carousel__playpause:hover{background-color:var(--mk-surface-2)}.mk-carousel__playpause:focus-visible{outline:var(--mk-focus-ring-width) solid var(--mk-focus-ring);outline-offset:var(--mk-focus-ring-offset)}.mk-carousel__arrow{position:absolute;top:50%;transform:translateY(-50%);display:grid;place-items:center;width:2rem;height:2rem;font-size:var(--mk-font-size-lg);line-height:1;color:var(--mk-text);background-color:var(--mk-surface);border:var(--mk-border-width) solid var(--mk-border);border-radius:var(--mk-radius-circle);box-shadow:var(--mk-shadow-sm);cursor:pointer;transition:background-color var(--mk-duration-fast) var(--mk-ease-standard)}.mk-carousel__arrow:hover{background-color:var(--mk-surface-2)}.mk-carousel__arrow:focus-visible{outline:var(--mk-focus-ring-width) solid var(--mk-focus-ring);outline-offset:var(--mk-focus-ring-offset)}.mk-carousel__arrow--prev{inset-inline-start:var(--mk-space-2)}.mk-carousel__arrow--next{inset-inline-end:var(--mk-space-2)}.mk-carousel__arrow:dir(rtl) span{display:inline-block;transform:scaleX(-1)}.mk-carousel__dots{display:flex;justify-content:center;gap:var(--mk-space-2);margin-top:var(--mk-space-2)}.mk-carousel__dot{width:.5rem;height:.5rem;padding:0;background-color:var(--mk-border-strong);border:none;border-radius:var(--mk-radius-circle);cursor:pointer;transition:background-color var(--mk-duration-fast) var(--mk-ease-standard),transform var(--mk-duration-fast) var(--mk-ease-standard)}.mk-carousel__dot:hover{background-color:var(--mk-text-muted)}.mk-carousel__dot:focus-visible{outline:var(--mk-focus-ring-width) solid var(--mk-focus-ring);outline-offset:var(--mk-focus-ring-offset)}.mk-carousel__dot--active{background-color:var(--mk-primary);transform:scale(1.25)}@media(prefers-reduced-motion:reduce){.mk-carousel__track,.mk-carousel__arrow,.mk-carousel__dot{transition:none}}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush });
3993
4778
  }
3994
4779
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.7", ngImport: i0, type: MkCarousel, decorators: [{
3995
4780
  type: Component,
3996
- args: [{ selector: 'mk-carousel', changeDetection: ChangeDetectionStrategy.OnPush, host: { class: 'mk-carousel' }, template: "<div\n class=\"mk-carousel__viewport\"\n role=\"region\"\n aria-roledescription=\"carousel\"\n [attr.aria-label]=\"ariaLabel()\"\n tabindex=\"0\"\n (keydown)=\"onKeydown($event)\"\n (mouseenter)=\"pause()\"\n (mouseleave)=\"resume()\"\n (focusin)=\"pause()\"\n (focusout)=\"resume()\"\n (pointerdown)=\"onPointerDown($event)\"\n (pointermove)=\"onPointerMove($event)\"\n (pointerup)=\"onPointerUp($event)\"\n (pointercancel)=\"onPointerUp($event)\"\n>\n @if (autoplay()) {\n <button\n type=\"button\"\n class=\"mk-carousel__playpause\"\n [attr.aria-label]=\"userPaused() ? i18n.playSlideshow : i18n.pauseSlideshow\"\n [attr.aria-pressed]=\"userPaused()\"\n (click)=\"toggleUserPause()\"\n >\n <span aria-hidden=\"true\">{{ userPaused() ? '\u25B6' : '\u23F8' }}</span>\n </button>\n }\n <div\n class=\"mk-carousel__track\"\n [class.mk-carousel__track--dragging]=\"dragging()\"\n [style.transform]=\"trackTransform()\"\n >\n <ng-content />\n </div>\n\n @if (showArrows() && count() > 1) {\n <button\n type=\"button\"\n class=\"mk-carousel__arrow mk-carousel__arrow--prev\"\n [attr.aria-label]=\"i18n.previousSlide\"\n (click)=\"prev()\"\n >\n <span aria-hidden=\"true\">\u2039</span>\n </button>\n <button\n type=\"button\"\n class=\"mk-carousel__arrow mk-carousel__arrow--next\"\n [attr.aria-label]=\"i18n.nextSlide\"\n (click)=\"next()\"\n >\n <span aria-hidden=\"true\">\u203A</span>\n </button>\n }\n</div>\n\n@if (showDots() && count() > 1) {\n <div class=\"mk-carousel__dots\">\n @for (dot of dots(); track dot) {\n <button\n type=\"button\"\n class=\"mk-carousel__dot\"\n [class.mk-carousel__dot--active]=\"dot === index()\"\n [attr.aria-current]=\"dot === index() || null\"\n [attr.aria-label]=\"i18n.goToSlide(dot + 1)\"\n (click)=\"goTo(dot)\"\n ></button>\n }\n </div>\n}\n\n<div class=\"mk-visually-hidden\" [attr.aria-live]=\"liveMode()\">{{ liveText() }}</div>\n", styles: ["@charset \"UTF-8\";:host{display:block;font-family:var(--mk-font-sans)}.mk-carousel__viewport{position:relative;overflow:hidden;border-radius:var(--mk-radius-md);touch-action:pan-y}.mk-carousel__viewport:focus-visible{outline:var(--mk-focus-ring-width) solid var(--mk-focus-ring);outline-offset:var(--mk-focus-ring-offset)}.mk-carousel__track{display:flex;transition:transform var(--mk-duration-normal, .24s) var(--mk-ease-standard)}.mk-carousel__track--dragging{transition:none}.mk-carousel__slide{flex:0 0 100%;min-width:0}.mk-carousel__playpause{position:absolute;top:var(--mk-space-2);inset-inline-start:var(--mk-space-2);z-index:1;display:grid;place-items:center;width:2rem;height:2rem;padding:0;font-size:var(--mk-font-size-sm);line-height:1;color:var(--mk-text);background-color:var(--mk-surface);border:var(--mk-border-width) solid var(--mk-border);border-radius:var(--mk-radius-circle);box-shadow:var(--mk-shadow-sm);cursor:pointer;transition:background-color var(--mk-duration-fast) var(--mk-ease-standard)}.mk-carousel__playpause:hover{background-color:var(--mk-surface-2)}.mk-carousel__playpause:focus-visible{outline:var(--mk-focus-ring-width) solid var(--mk-focus-ring);outline-offset:var(--mk-focus-ring-offset)}.mk-carousel__arrow{position:absolute;top:50%;transform:translateY(-50%);display:grid;place-items:center;width:2rem;height:2rem;font-size:var(--mk-font-size-lg);line-height:1;color:var(--mk-text);background-color:var(--mk-surface);border:var(--mk-border-width) solid var(--mk-border);border-radius:var(--mk-radius-circle);box-shadow:var(--mk-shadow-sm);cursor:pointer;transition:background-color var(--mk-duration-fast) var(--mk-ease-standard)}.mk-carousel__arrow:hover{background-color:var(--mk-surface-2)}.mk-carousel__arrow:focus-visible{outline:var(--mk-focus-ring-width) solid var(--mk-focus-ring);outline-offset:var(--mk-focus-ring-offset)}.mk-carousel__arrow--prev{inset-inline-start:var(--mk-space-2)}.mk-carousel__arrow--next{inset-inline-end:var(--mk-space-2)}.mk-carousel__arrow:dir(rtl) span{display:inline-block;transform:scaleX(-1)}.mk-carousel__dots{display:flex;justify-content:center;gap:var(--mk-space-2);margin-top:var(--mk-space-2)}.mk-carousel__dot{width:.5rem;height:.5rem;padding:0;background-color:var(--mk-border-strong);border:none;border-radius:var(--mk-radius-circle);cursor:pointer;transition:background-color var(--mk-duration-fast) var(--mk-ease-standard),transform var(--mk-duration-fast) var(--mk-ease-standard)}.mk-carousel__dot:hover{background-color:var(--mk-text-muted)}.mk-carousel__dot:focus-visible{outline:var(--mk-focus-ring-width) solid var(--mk-focus-ring);outline-offset:var(--mk-focus-ring-offset)}.mk-carousel__dot--active{background-color:var(--mk-primary);transform:scale(1.25)}@media(prefers-reduced-motion:reduce){.mk-carousel__track,.mk-carousel__arrow,.mk-carousel__dot{transition:none}}\n"] }]
4781
+ args: [{ selector: 'mk-carousel', changeDetection: ChangeDetectionStrategy.OnPush, host: { class: 'mk-carousel' }, template: "<div\n class=\"mk-carousel__viewport\"\n role=\"region\"\n aria-roledescription=\"carousel\"\n [attr.aria-label]=\"ariaLabel()\"\n tabindex=\"0\"\n (keydown)=\"onKeydown($event)\"\n (mouseenter)=\"pause()\"\n (mouseleave)=\"resume()\"\n (focusin)=\"pause()\"\n (focusout)=\"resume()\"\n (pointerdown)=\"onPointerDown($event)\"\n (pointermove)=\"onPointerMove($event)\"\n (pointerup)=\"onPointerUp($event)\"\n (pointercancel)=\"onPointerUp($event)\"\n>\n @if (autoplay()) {\n <button\n type=\"button\"\n class=\"mk-carousel__playpause\"\n [attr.aria-label]=\"userPaused() ? i18n.playSlideshow : i18n.pauseSlideshow\"\n [attr.aria-pressed]=\"userPaused()\"\n (click)=\"toggleUserPause()\"\n >\n <span aria-hidden=\"true\">{{ userPaused() ? '\u25B6' : '\u23F8' }}</span>\n </button>\n }\n <div\n class=\"mk-carousel__track\"\n [class.mk-carousel__track--dragging]=\"dragging()\"\n [style.transform]=\"trackTransform()\"\n >\n <ng-content />\n </div>\n\n @if (showArrows() && count() > 1) {\n <button\n type=\"button\"\n class=\"mk-carousel__arrow mk-carousel__arrow--prev\"\n [attr.aria-label]=\"i18n.previousSlide\"\n (click)=\"prev()\"\n >\n <span aria-hidden=\"true\">\u2039</span>\n </button>\n <button\n type=\"button\"\n class=\"mk-carousel__arrow mk-carousel__arrow--next\"\n [attr.aria-label]=\"i18n.nextSlide\"\n (click)=\"next()\"\n >\n <span aria-hidden=\"true\">\u203A</span>\n </button>\n }\n</div>\n\n@if (showDots() && count() > 1) {\n <div class=\"mk-carousel__dots\">\n @for (dot of dots(); track dot) {\n <button\n type=\"button\"\n class=\"mk-carousel__dot\"\n [class.mk-carousel__dot--active]=\"dot === index()\"\n [attr.aria-current]=\"dot === index() || null\"\n [attr.aria-label]=\"i18n.goToSlide(dot + 1)\"\n (click)=\"goTo(dot)\"\n ></button>\n }\n </div>\n}\n\n<div class=\"mk-visually-hidden\" [attr.aria-live]=\"liveMode()\">{{ liveText() }}</div>\n", styles: ["@charset \"UTF-8\";:host{display:block;font-family:var(--mk-font-sans)}.mk-carousel__viewport{position:relative;overflow:hidden;border-radius:var(--mk-radius-md);touch-action:pan-y}.mk-carousel__viewport:focus-visible{outline:var(--mk-focus-ring-width) solid var(--mk-focus-ring);outline-offset:var(--mk-focus-ring-offset)}.mk-carousel__track{display:flex;transition:transform var(--mk-duration-normal, .24s) var(--mk-ease-standard)}.mk-carousel__track--dragging{transition:none}:host ::ng-deep .mk-carousel__slide{flex:0 0 100%;min-width:0;box-sizing:border-box}.mk-carousel__playpause{position:absolute;top:var(--mk-space-2);inset-inline-start:var(--mk-space-2);z-index:1;display:grid;place-items:center;width:2rem;height:2rem;padding:0;font-size:var(--mk-font-size-sm);line-height:1;color:var(--mk-text);background-color:var(--mk-surface);border:var(--mk-border-width) solid var(--mk-border);border-radius:var(--mk-radius-circle);box-shadow:var(--mk-shadow-sm);cursor:pointer;transition:background-color var(--mk-duration-fast) var(--mk-ease-standard)}.mk-carousel__playpause:hover{background-color:var(--mk-surface-2)}.mk-carousel__playpause:focus-visible{outline:var(--mk-focus-ring-width) solid var(--mk-focus-ring);outline-offset:var(--mk-focus-ring-offset)}.mk-carousel__arrow{position:absolute;top:50%;transform:translateY(-50%);display:grid;place-items:center;width:2rem;height:2rem;font-size:var(--mk-font-size-lg);line-height:1;color:var(--mk-text);background-color:var(--mk-surface);border:var(--mk-border-width) solid var(--mk-border);border-radius:var(--mk-radius-circle);box-shadow:var(--mk-shadow-sm);cursor:pointer;transition:background-color var(--mk-duration-fast) var(--mk-ease-standard)}.mk-carousel__arrow:hover{background-color:var(--mk-surface-2)}.mk-carousel__arrow:focus-visible{outline:var(--mk-focus-ring-width) solid var(--mk-focus-ring);outline-offset:var(--mk-focus-ring-offset)}.mk-carousel__arrow--prev{inset-inline-start:var(--mk-space-2)}.mk-carousel__arrow--next{inset-inline-end:var(--mk-space-2)}.mk-carousel__arrow:dir(rtl) span{display:inline-block;transform:scaleX(-1)}.mk-carousel__dots{display:flex;justify-content:center;gap:var(--mk-space-2);margin-top:var(--mk-space-2)}.mk-carousel__dot{width:.5rem;height:.5rem;padding:0;background-color:var(--mk-border-strong);border:none;border-radius:var(--mk-radius-circle);cursor:pointer;transition:background-color var(--mk-duration-fast) var(--mk-ease-standard),transform var(--mk-duration-fast) var(--mk-ease-standard)}.mk-carousel__dot:hover{background-color:var(--mk-text-muted)}.mk-carousel__dot:focus-visible{outline:var(--mk-focus-ring-width) solid var(--mk-focus-ring);outline-offset:var(--mk-focus-ring-offset)}.mk-carousel__dot--active{background-color:var(--mk-primary);transform:scale(1.25)}@media(prefers-reduced-motion:reduce){.mk-carousel__track,.mk-carousel__arrow,.mk-carousel__dot{transition:none}}\n"] }]
3997
4782
  }], ctorParameters: () => [], propDecorators: { slides: [{ type: i0.ContentChildren, args: [i0.forwardRef(() => MkCarouselSlide), { isSignal: true }] }], index: [{ type: i0.Input, args: [{ isSignal: true, alias: "index", required: false }] }, { type: i0.Output, args: ["indexChange"] }], ariaLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "ariaLabel", required: false }] }], loop: [{ type: i0.Input, args: [{ isSignal: true, alias: "loop", required: false }] }], showDots: [{ type: i0.Input, args: [{ isSignal: true, alias: "showDots", required: false }] }], showArrows: [{ type: i0.Input, args: [{ isSignal: true, alias: "showArrows", required: false }] }], autoplay: [{ type: i0.Input, args: [{ isSignal: true, alias: "autoplay", required: false }] }], interval: [{ type: i0.Input, args: [{ isSignal: true, alias: "interval", required: false }] }], userPaused: [{ type: i0.Input, args: [{ isSignal: true, alias: "userPaused", required: false }] }, { type: i0.Output, args: ["userPausedChange"] }] } });
3998
4783
 
3999
4784
  /**
@@ -6137,5 +6922,5 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.7", ngImpor
6137
6922
  * Generated bundle index. Do not edit.
6138
6923
  */
6139
6924
 
6140
- export { MK_CHART_PALETTE_SIZE, MkAvatar, MkAvatarGroup, MkBadge, MkBarChart, MkCalendarHeatmap, MkCard, MkCardFooter, MkCardHeader, MkCardTitle, MkCarousel, MkCarouselSlide, MkCode, MkCountdown, MkDescItem, MkDescriptionList, MkDiff, MkDivider, MkDonutChart, MkEmptyState, MkFunnelChart, MkGauge, MkHeatmap, MkInlineEdit, MkJsonViewer, MkKanban, MkLineChart, MkList, MkListItem, MkLogViewer, MkMarkdown, MkProfileActions, MkProfileCard, MkProfileMeta, MkProgressBar, MkProgressRing, MkQrCode, MkRadarChart, MkScatterChart, MkSkeleton, MkSkeletonPreset, MkSparkline, MkSpinner, MkStatCard, MkTag, MkTimeline, MkTimelineItem, MkTreemap, MkVirtualScroll, mkArcPath, mkAreaPath, mkBuildJsonTree, mkChartColor, mkComputeDiff, mkDiffStats, mkEncodeQr, mkFormatCompact, mkLinePath, mkLinearScale, mkNiceTicks, mkParseAnsi, mkParseMarkdown, mkRenderMarkdown, mkSplitDuration, mkSquarify, mkStripAnsi };
6925
+ export { MK_CHART_PALETTE_SIZE, MK_HEATMAP_MIN_CONTRAST, MkAvatar, MkAvatarGroup, MkBadge, MkBadgeOverlay, MkBarChart, MkCalendarHeatmap, MkCard, MkCardFooter, MkCardHeader, MkCardTitle, MkCarousel, MkCarouselSlide, MkCode, MkCountdown, MkDescItem, MkDescriptionList, MkDiff, MkDivider, MkDonutChart, MkEmptyState, MkFunnelChart, MkGauge, MkHeatmap, MkInlineEdit, MkJsonViewer, MkKanban, MkLineChart, MkList, MkListItem, MkLogViewer, MkMarkdown, MkOrgChart, MkOrgChartNodeDef, MkProfileActions, MkProfileCard, MkProfileMeta, MkProgressBar, MkProgressRing, MkQrCode, MkRadarChart, MkScatterChart, MkSkeleton, MkSkeletonPreset, MkSparkline, MkSpinner, MkStatCard, MkTag, MkTimeline, MkTimelineItem, MkTreemap, MkVirtualScroll, mkArcPath, mkAreaPath, mkBuildJsonTree, mkChartColor, mkComputeDiff, mkContrastRatio, mkDiffStats, mkEncodeQr, mkFormatCompact, mkHeatmapCellColors, mkLinePath, mkLinearScale, mkMixRgb, mkNiceTicks, mkOrgChartFromFlat, mkParseAnsi, mkParseMarkdown, mkParseRgb, mkRelativeLuminance, mkRenderMarkdown, mkSplitDuration, mkSquarify, mkStripAnsi };
6141
6926
  //# sourceMappingURL=mk-kit-ui-data.mjs.map