@nanahoshi/mona-ui 0.24.1 → 0.24.2

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 (33) hide show
  1. package/README.md +1 -0
  2. package/fesm2022/nanahoshi-mona-ui-button-group.mjs +1 -1
  3. package/fesm2022/nanahoshi-mona-ui-button.mjs +122 -60
  4. package/fesm2022/nanahoshi-mona-ui-calendar.mjs +1 -2
  5. package/fesm2022/nanahoshi-mona-ui-chip.mjs +1 -1
  6. package/fesm2022/nanahoshi-mona-ui-color-gradient.mjs +1 -1
  7. package/fesm2022/nanahoshi-mona-ui-color-picker.mjs +1 -1
  8. package/fesm2022/nanahoshi-mona-ui-date-picker.mjs +1 -1
  9. package/fesm2022/nanahoshi-mona-ui-datetime-picker.mjs +1 -1
  10. package/fesm2022/nanahoshi-mona-ui-dialog.mjs +1 -1
  11. package/fesm2022/nanahoshi-mona-ui-dropdown-button.mjs +1 -1
  12. package/fesm2022/nanahoshi-mona-ui-editor.mjs +13 -13
  13. package/fesm2022/nanahoshi-mona-ui-filter.mjs +1 -1
  14. package/fesm2022/{nanahoshi-mona-ui-grid-grid-footer-row.component-CnPhVIr4.mjs → nanahoshi-mona-ui-grid-grid-footer-row.component-x_euoNnS.mjs} +2 -2
  15. package/fesm2022/{nanahoshi-mona-ui-grid-grid-list.component-DxY6bfTX.mjs → nanahoshi-mona-ui-grid-grid-list.component-C1_6vq77.mjs} +4 -4
  16. package/fesm2022/{nanahoshi-mona-ui-grid-grid-row.component-CaO5Lae6.mjs → nanahoshi-mona-ui-grid-grid-row.component-BhukVWIy.mjs} +3 -3
  17. package/fesm2022/{nanahoshi-mona-ui-grid-grid-virtual-list.component-jNYtqg5B.mjs → nanahoshi-mona-ui-grid-grid-virtual-list.component-XQKOPPVs.mjs} +4 -4
  18. package/fesm2022/{nanahoshi-mona-ui-grid-nanahoshi-mona-ui-grid-9FtfCutf.mjs → nanahoshi-mona-ui-grid-nanahoshi-mona-ui-grid-Iw-wvKGl.mjs} +13 -12
  19. package/fesm2022/nanahoshi-mona-ui-grid.mjs +1 -1
  20. package/fesm2022/nanahoshi-mona-ui-list-box.mjs +1 -1
  21. package/fesm2022/nanahoshi-mona-ui-notification.mjs +1 -1
  22. package/fesm2022/nanahoshi-mona-ui-numeric-text-box.mjs +2 -2
  23. package/fesm2022/nanahoshi-mona-ui-pager.mjs +1 -1
  24. package/fesm2022/nanahoshi-mona-ui-sheet.mjs +1 -1
  25. package/fesm2022/nanahoshi-mona-ui-split-button.mjs +1 -1
  26. package/fesm2022/nanahoshi-mona-ui-splitter.mjs +1 -1
  27. package/fesm2022/nanahoshi-mona-ui-tabs.mjs +1 -1
  28. package/fesm2022/nanahoshi-mona-ui-text-box.mjs +1 -1
  29. package/fesm2022/nanahoshi-mona-ui-time-picker.mjs +1 -1
  30. package/fesm2022/nanahoshi-mona-ui-time-selector.mjs +1 -1
  31. package/fesm2022/nanahoshi-mona-ui-window.mjs +1 -1
  32. package/package.json +1 -1
  33. package/types/nanahoshi-mona-ui-button.d.ts +44 -20
package/README.md CHANGED
@@ -18,6 +18,7 @@ A modern, high-performance, accessible UI component library built for Angular an
18
18
  ## Documentation
19
19
 
20
20
  - [Internationalization (i18n) & RTL Guide](docs/i18n.md)
21
+ - [Buttons](docs/button.md)
21
22
  - [Patch Stores & Merge Utilities](docs/patch-store.md)
22
23
  - [Component Migration Inventory](docs/internal/i18n-rtl-migration-inventory.md)
23
24
 
@@ -21,7 +21,6 @@ const buttonGroupThemeVariants = cva(`
21
21
  [&>button:not(:last-child)]:border-e
22
22
  [&>button:not(:last-child)]:border-border-subtle
23
23
  [&>button]:rounded-none
24
- [&>button]:focus-visible:ring-2
25
24
  [&>button]:focus-visible:z-10
26
25
  `, {
27
26
  variants: {
@@ -149,6 +148,7 @@ class ButtonGroupComponent {
149
148
  * @default ""
150
149
  */
151
150
  this.userClass = input("", { ...(ngDevMode ? { debugName: "userClass" } : /* istanbul ignore next */ {}), alias: "class" });
151
+ this.#buttonService.setMembers(this.buttons);
152
152
  effect(() => {
153
153
  const disabled = this.disabled();
154
154
  untracked(() => this.#buttonService.groupDisabled.set(disabled));
@@ -1,5 +1,5 @@
1
1
  import * as i0 from '@angular/core';
2
- import { signal, Injectable, inject, ApplicationRef, DestroyRef, ElementRef, Injector, Renderer2, computed, input, model, effect, untracked, afterNextRender, createComponent, Directive } from '@angular/core';
2
+ import { signal, computed, Injectable, inject, ApplicationRef, DestroyRef, ElementRef, Injector, Renderer2, input, booleanAttribute, model, numberAttribute, effect, untracked, afterNextRender, isDevMode, createComponent, afterRenderEffect, Directive } from '@angular/core';
3
3
  import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
4
4
  import { IndicatorIconComponent } from '@nanahoshi/mona-ui/internal/indicator-icon';
5
5
  import { Subject, fromEvent, takeWhile } from 'rxjs';
@@ -7,8 +7,15 @@ import { twMerge } from 'tailwind-merge';
7
7
  import { cva } from 'class-variance-authority';
8
8
  import { themeControlSurfaceClasses } from '@nanahoshi/mona-ui/internal';
9
9
 
10
+ /**
11
+ * Coordinates a `mona-button-group` with its buttons: the group publishes its look, size, rounding, disabled state
12
+ * and members here, and buttons report clicks and receive selection changes through it. It is public so the
13
+ * button-group entry point can provide it; applications don't need to use it directly.
14
+ */
10
15
  class ButtonService {
11
16
  constructor() {
17
+ this.#members = signal(null, /* @ts-ignore */
18
+ ...(ngDevMode ? [{ debugName: "#members" }] : /* istanbul ignore next */ []));
12
19
  this.buttonClick$ = new Subject();
13
20
  this.buttonSelect$ = new Subject();
14
21
  this.groupDisabled = signal(false, /* @ts-ignore */
@@ -19,6 +26,19 @@ class ButtonService {
19
26
  ...(ngDevMode ? [{ debugName: "groupRounded" }] : /* istanbul ignore next */ []));
20
27
  this.groupSize = signal(undefined, /* @ts-ignore */
21
28
  ...(ngDevMode ? [{ debugName: "groupSize" }] : /* istanbul ignore next */ []));
29
+ /**
30
+ * The buttons that belong to the group. Only these follow the group's look, size, rounding, disabled state and
31
+ * selection; other buttons that can inject this service ignore it.
32
+ */
33
+ this.members = computed(() => this.#members()?.() ?? [], /* @ts-ignore */
34
+ ...(ngDevMode ? [{ debugName: "members" }] : /* istanbul ignore next */ []));
35
+ }
36
+ #members;
37
+ /**
38
+ * Sets the source of the group's members, such as the group's `contentChildren(ButtonDirective)` query.
39
+ */
40
+ setMembers(members) {
41
+ this.#members.set(members);
22
42
  }
23
43
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.6", ngImport: i0, type: ButtonService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
24
44
  static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "22.0.6", ngImport: i0, type: ButtonService }); }
@@ -31,13 +51,13 @@ const buttonThemeVariants = cva(`
31
51
  inline-flex items-center justify-center gap-2
32
52
  cursor-pointer whitespace-nowrap
33
53
  text-sm font-medium
34
- outline-none
35
54
  transition-colors duration-100 ease-in-out
55
+ focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-focus-indicator
36
56
  `, {
37
57
  variants: {
38
58
  disabled: {
39
59
  true: `
40
- pointer-events-none cursor-not-allowed select-none
60
+ pointer-events-none select-none
41
61
  disabled:border-disabled-border disabled:bg-disabled-background disabled:text-disabled-foreground
42
62
  disabled:shadow-none
43
63
  `,
@@ -56,66 +76,57 @@ const buttonThemeVariants = cva(`
56
76
  ${themeControlSurfaceClasses} text-foreground
57
77
  border border-input-border
58
78
  hover:bg-hover active:bg-active
59
- focus-visible:border-focus-indicator focus-visible:ring-2 focus-visible:ring-focus-indicator/35
79
+ focus-visible:border-focus-indicator
60
80
  `,
61
81
  primary: `
62
82
  bg-primary text-primary-foreground
63
83
  hover:bg-primary-hover active:bg-primary-active
64
- focus-visible:ring-2 focus-visible:ring-focus-indicator/35
65
84
  `,
66
85
  success: `
67
86
  bg-success text-success-foreground
68
87
  hover:bg-success-hover
69
88
  active:bg-success-active
70
- focus-visible:ring-2 focus-visible:ring-success/35
71
89
  `,
72
90
  error: `
73
91
  bg-error text-error-foreground
74
92
  hover:bg-error-hover
75
93
  active:bg-error-active
76
- focus-visible:ring-2 focus-visible:ring-error/35
77
94
  `,
78
95
  warning: `
79
96
  bg-warning text-warning-foreground
80
97
  hover:bg-warning-hover
81
98
  active:bg-warning-active
82
- focus-visible:ring-2 focus-visible:ring-warning/35
83
99
  `,
84
100
  info: `
85
101
  bg-info text-info-foreground
86
102
  hover:bg-info-hover
87
103
  active:bg-info-active
88
- focus-visible:ring-2 focus-visible:ring-info/35
89
104
  `,
90
105
  outline: `
91
106
  ${themeControlSurfaceClasses} text-foreground
92
107
  border border-input-border
93
108
  hover:bg-hover active:bg-active
94
- focus-visible:border-focus-indicator focus-visible:ring-2 focus-visible:ring-focus-indicator/35
109
+ focus-visible:border-focus-indicator
95
110
  `,
96
111
  secondary: `
97
112
  bg-secondary text-secondary-foreground
98
113
  hover:bg-secondary-hover
99
114
  active:bg-secondary-active
100
- focus-visible:ring-2 focus-visible:ring-focus-indicator/35
101
115
  `,
102
116
  ghost: `
103
117
  bg-transparent text-foreground
104
118
  shadow-none
105
119
  hover:bg-hover active:bg-active
106
- focus-visible:ring-2 focus-visible:ring-focus-indicator/35
107
120
  `,
108
121
  link: `
109
122
  bg-transparent text-foreground
110
123
  shadow-none
111
124
  underline-offset-4 hover:underline
112
- focus-visible:ring-2 focus-visible:ring-focus-indicator/35
113
125
  `,
114
126
  clear: `
115
127
  bg-transparent
116
128
  border-0 shadow-none
117
129
  hover:bg-transparent active:bg-transparent
118
- focus-visible:ring-2 focus-visible:ring-focus-indicator/35
119
130
  `
120
131
  },
121
132
  rounded: {
@@ -240,19 +251,21 @@ const buttonThemeVariants = cva(`
240
251
  },
241
252
  {
242
253
  iconOnly: true,
243
- loading: false,
254
+ loading: true,
255
+ class: "[&>:not(mona-indicator-icon)]:hidden"
256
+ },
257
+ {
258
+ iconOnly: true,
244
259
  size: "small",
245
260
  class: "h-8 w-8 p-0"
246
261
  },
247
262
  {
248
263
  iconOnly: true,
249
- loading: false,
250
264
  size: "medium",
251
265
  class: "h-9 w-9 p-0"
252
266
  },
253
267
  {
254
268
  iconOnly: true,
255
- loading: false,
256
269
  size: "large",
257
270
  class: "h-10 w-10 p-0"
258
271
  }
@@ -268,6 +281,11 @@ class ButtonDirective {
268
281
  #appRef;
269
282
  #buttonService;
270
283
  #destroyRef;
284
+ /**
285
+ * The service of the group this button belongs to. A `ButtonService` higher up the injector tree is not enough:
286
+ * buttons inside a component projected into a group, or inside a popup opened from one, are not members.
287
+ */
288
+ #group;
271
289
  #hostElementRef;
272
290
  #injector;
273
291
  #renderer;
@@ -277,25 +295,17 @@ class ButtonDirective {
277
295
  this.#appRef = inject(ApplicationRef);
278
296
  this.#buttonService = inject(ButtonService, { optional: true });
279
297
  this.#destroyRef = inject(DestroyRef);
298
+ /**
299
+ * The service of the group this button belongs to. A `ButtonService` higher up the injector tree is not enough:
300
+ * buttons inside a component projected into a group, or inside a popup opened from one, are not members.
301
+ */
302
+ this.#group = computed(() => (this.#buttonService?.members().includes(this) ? this.#buttonService : null), /* @ts-ignore */
303
+ ...(ngDevMode ? [{ debugName: "#group" }] : /* istanbul ignore next */ []));
280
304
  this.#hostElementRef = inject(ElementRef);
281
305
  this.#injector = inject(Injector);
282
306
  this.#renderer = inject(Renderer2);
283
307
  this.#loaderComponentRef = null;
284
308
  this.#toggleSubscription = null;
285
- this.displaysPressedState = computed(() => this.isInButtonGroup() || !!this.toggleable(), /* @ts-ignore */
286
- ...(ngDevMode ? [{ debugName: "displaysPressedState" }] : /* istanbul ignore next */ []));
287
- this.effectiveDisabled = computed(() => this.#buttonService?.groupDisabled() || this.disabled(), /* @ts-ignore */
288
- ...(ngDevMode ? [{ debugName: "effectiveDisabled" }] : /* istanbul ignore next */ []));
289
- this.effectiveLook = computed(() => this.#buttonService?.groupLook() ?? this.look(), /* @ts-ignore */
290
- ...(ngDevMode ? [{ debugName: "effectiveLook" }] : /* istanbul ignore next */ []));
291
- this.effectiveRounded = computed(() => this.#buttonService?.groupRounded() ?? this.rounded(), /* @ts-ignore */
292
- ...(ngDevMode ? [{ debugName: "effectiveRounded" }] : /* istanbul ignore next */ []));
293
- this.effectiveSize = computed(() => this.#buttonService?.groupSize() ?? this.size(), /* @ts-ignore */
294
- ...(ngDevMode ? [{ debugName: "effectiveSize" }] : /* istanbul ignore next */ []));
295
- this.effectiveToggleable = computed(() => this.toggleable() ?? this.isInButtonGroup(), /* @ts-ignore */
296
- ...(ngDevMode ? [{ debugName: "effectiveToggleable" }] : /* istanbul ignore next */ []));
297
- this.isInButtonGroup = computed(() => !!this.#buttonService, /* @ts-ignore */
298
- ...(ngDevMode ? [{ debugName: "isInButtonGroup" }] : /* istanbul ignore next */ []));
299
309
  this.baseClass = computed(() => {
300
310
  const disabled = this.effectiveDisabled();
301
311
  const iconOnly = this.iconOnly();
@@ -309,6 +319,16 @@ class ButtonDirective {
309
319
  return twMerge(variantClasses, userClass);
310
320
  }, /* @ts-ignore */
311
321
  ...(ngDevMode ? [{ debugName: "baseClass" }] : /* istanbul ignore next */ []));
322
+ this.effectiveDisabled = computed(() => this.#group()?.groupDisabled() || this.disabled(), /* @ts-ignore */
323
+ ...(ngDevMode ? [{ debugName: "effectiveDisabled" }] : /* istanbul ignore next */ []));
324
+ this.effectiveLook = computed(() => this.#group()?.groupLook() ?? this.look(), /* @ts-ignore */
325
+ ...(ngDevMode ? [{ debugName: "effectiveLook" }] : /* istanbul ignore next */ []));
326
+ this.effectiveRounded = computed(() => this.#group()?.groupRounded() ?? this.rounded(), /* @ts-ignore */
327
+ ...(ngDevMode ? [{ debugName: "effectiveRounded" }] : /* istanbul ignore next */ []));
328
+ this.effectiveSize = computed(() => this.#group()?.groupSize() ?? this.size(), /* @ts-ignore */
329
+ ...(ngDevMode ? [{ debugName: "effectiveSize" }] : /* istanbul ignore next */ []));
330
+ this.effectiveToggleable = computed(() => this.toggleable() ?? !!this.#group(), /* @ts-ignore */
331
+ ...(ngDevMode ? [{ debugName: "effectiveToggleable" }] : /* istanbul ignore next */ []));
312
332
  this.loadingSize = computed(() => {
313
333
  const size = this.effectiveSize();
314
334
  switch (size) {
@@ -330,27 +350,29 @@ class ButtonDirective {
330
350
  this.ariaHasPopup = input("false", { ...(ngDevMode ? { debugName: "ariaHasPopup" } : /* istanbul ignore next */ {}), alias: "aria-haspopup" });
331
351
  /**
332
352
  * @description Renders the component with reduced visual emphasis and removes pointer interaction.
333
- * When inside a `ButtonGroup`, the group's disabled state takes precedence.
353
+ * Accepts the bare attribute form (`<button monaButton disabled>`).
354
+ * When inside a `ButtonGroup`, the button is disabled when either it or the group is disabled.
334
355
  * @default false
335
356
  */
336
- this.disabled = model(false, /* @ts-ignore */
337
- ...(ngDevMode ? [{ debugName: "disabled" }] : /* istanbul ignore next */ []));
357
+ this.disabled = input(false, { ...(ngDevMode ? { debugName: "disabled" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
338
358
  /**
339
359
  * @description Removes horizontal padding and fixes a square aspect ratio sized to match `size`.
340
- * Provide `aria-label` on the host when using icon-only buttons.
360
+ * Provide `aria-label` on the host when using icon-only buttons; in dev mode, an icon-only button without an
361
+ * accessible name logs a warning.
341
362
  * @default false
342
363
  */
343
- this.iconOnly = input(false, /* @ts-ignore */
344
- ...(ngDevMode ? [{ debugName: "iconOnly" }] : /* istanbul ignore next */ []));
364
+ this.iconOnly = input(false, { ...(ngDevMode ? { debugName: "iconOnly" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
345
365
  /**
346
366
  * @description Displays a loading indicator and prevents interaction while an operation is in progress.
347
- * Sets `aria-busy="true"` on the host.
367
+ * Sets `aria-busy="true"` and `aria-disabled="true"` on the host. The button stays focusable, so keyboard focus
368
+ * isn't lost when loading starts, and clicks (including form submission) are blocked until it ends.
348
369
  * @default false
349
370
  */
350
- this.loading = model(false, /* @ts-ignore */
351
- ...(ngDevMode ? [{ debugName: "loading" }] : /* istanbul ignore next */ []));
371
+ this.loading = input(false, { ...(ngDevMode ? { debugName: "loading" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
352
372
  /**
353
373
  * @description Visual style variant of the button. When inside a `ButtonGroup`, the group's look takes precedence.
374
+ * `"outline"` looks the same as `"default"`. `"clear"` shows no selected state, so use another look for
375
+ * toggle buttons.
354
376
  * @default "default"
355
377
  */
356
378
  this.look = model("default", /* @ts-ignore */
@@ -377,11 +399,17 @@ class ButtonDirective {
377
399
  this.size = input("medium", /* @ts-ignore */
378
400
  ...(ngDevMode ? [{ debugName: "size" }] : /* istanbul ignore next */ []));
379
401
  /**
380
- * @description Tab index of the host element. Automatically overridden to `-1` when the button is disabled or loading.
381
- * Accepts a numeric string and converts it to a number.
402
+ * @description Tab index of the host element. Automatically overridden to `-1` when the button is disabled.
403
+ * Accepts a numeric string and converts it to a number; a value that is not a number falls back to `0`.
382
404
  * @default 0
383
405
  */
384
- this.tabindex = input(0, { ...(ngDevMode ? { debugName: "tabindex" } : /* istanbul ignore next */ {}), transform: (value) => (typeof value === "string" ? parseInt(value, 10) : value) });
406
+ this.tabindex = input(0, { ...(ngDevMode ? { debugName: "tabindex" } : /* istanbul ignore next */ {}), transform: (value) => numberAttribute(value, 0) });
407
+ /**
408
+ * @description Enables toggle behavior — each click flips the `selected` state and `aria-pressed` is managed.
409
+ * Accepts the bare attribute form. Buttons in a `ButtonGroup` are toggleable unless this is set to `false`.
410
+ * @default undefined
411
+ */
412
+ this.toggleable = input(undefined, { ...(ngDevMode ? { debugName: "toggleable" } : /* istanbul ignore next */ {}), transform: (value) => (value === undefined ? undefined : booleanAttribute(value)) });
385
413
  /**
386
414
  * @description Native `type` attribute of the button. Defaults to `"button"` to prevent accidental
387
415
  * form submission; set to `"submit"` or `"reset"` explicitly when that behavior is intended.
@@ -389,13 +417,6 @@ class ButtonDirective {
389
417
  */
390
418
  this.type = input("button", /* @ts-ignore */
391
419
  ...(ngDevMode ? [{ debugName: "type" }] : /* istanbul ignore next */ []));
392
- /**
393
- * @description Enables toggle behavior — each click flips the `selected` state and `aria-pressed` is managed.
394
- * Must use `[toggleable]="true"` binding syntax, not bare attribute form.
395
- * @default undefined
396
- */
397
- this.toggleable = input(/* @ts-ignore */
398
- ...(ngDevMode ? [undefined, { debugName: "toggleable" }] : /* istanbul ignore next */ []));
399
420
  /**
400
421
  * @description Additional CSS classes merged onto the host element via `tailwind-merge`.
401
422
  * @default ""
@@ -419,12 +440,35 @@ class ButtonDirective {
419
440
  }
420
441
  });
421
442
  });
422
- afterNextRender({
423
- read: () => this.#setSubscriptions()
424
- });
443
+ this.#blockClicksWhileLoading();
444
+ this.#destroyRef.onDestroy(() => this.#removeLoader());
445
+ if (this.#buttonService) {
446
+ afterNextRender({
447
+ read: () => this.#setSubscriptions()
448
+ });
449
+ }
450
+ if (isDevMode()) {
451
+ this.#warnIfIconOnlyWithoutName();
452
+ }
453
+ }
454
+ /**
455
+ * A loading button keeps focus, so it is not natively disabled. A capturing listener registered before any other
456
+ * stops activation from reaching the user's handlers, the toggle handler and form submission.
457
+ */
458
+ #blockClicksWhileLoading() {
459
+ const host = this.#hostElementRef.nativeElement;
460
+ const listener = (event) => {
461
+ if (this.loading()) {
462
+ event.preventDefault();
463
+ event.stopImmediatePropagation();
464
+ }
465
+ };
466
+ host.addEventListener("click", listener, { capture: true });
467
+ this.#destroyRef.onDestroy(() => host.removeEventListener("click", listener, { capture: true }));
425
468
  }
426
469
  #createLoader(size) {
427
470
  if (this.#loaderComponentRef) {
471
+ this.#loaderComponentRef.setInput("size", size);
428
472
  return;
429
473
  }
430
474
  this.#loaderComponentRef = createComponent(IndicatorIconComponent, {
@@ -453,6 +497,11 @@ class ButtonDirective {
453
497
  }
454
498
  });
455
499
  }
500
+ #hasAccessibleName() {
501
+ const host = this.#hostElementRef.nativeElement;
502
+ const named = ["aria-label", "aria-labelledby", "title"].some(name => !!host.getAttribute(name)?.trim());
503
+ return named || !!host.textContent?.trim();
504
+ }
456
505
  #setToggleableEvent() {
457
506
  this.#toggleSubscription?.unsubscribe();
458
507
  this.#toggleSubscription = fromEvent(this.#hostElementRef.nativeElement, "click")
@@ -462,16 +511,29 @@ class ButtonDirective {
462
511
  return;
463
512
  }
464
513
  const wasSelected = this.selected();
465
- if (this.#buttonService) {
466
- this.#buttonService.buttonClick$.next([this, wasSelected]);
514
+ const group = this.#group();
515
+ if (group) {
516
+ group.buttonClick$.next([this, wasSelected]);
467
517
  }
468
518
  else {
469
519
  this.selected.set(!this.selected());
470
520
  }
471
521
  });
472
522
  }
523
+ #warnIfIconOnlyWithoutName() {
524
+ let warned = false;
525
+ afterRenderEffect({
526
+ read: () => {
527
+ if (warned || !this.iconOnly() || this.#hasAccessibleName()) {
528
+ return;
529
+ }
530
+ warned = true;
531
+ console.warn("[Mona Button] An icon-only button needs an accessible name. Add aria-label, aria-labelledby or title.", this.#hostElementRef.nativeElement);
532
+ }
533
+ });
534
+ }
473
535
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.6", ngImport: i0, type: ButtonDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
474
- static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "22.0.6", type: ButtonDirective, isStandalone: true, selector: "button[monaButton]", inputs: { ariaHasPopup: { classPropertyName: "ariaHasPopup", publicName: "aria-haspopup", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, iconOnly: { classPropertyName: "iconOnly", publicName: "iconOnly", isSignal: true, isRequired: false, transformFunction: null }, loading: { classPropertyName: "loading", publicName: "loading", isSignal: true, isRequired: false, transformFunction: null }, look: { classPropertyName: "look", publicName: "look", isSignal: true, isRequired: false, transformFunction: null }, rounded: { classPropertyName: "rounded", publicName: "rounded", isSignal: true, isRequired: false, transformFunction: null }, selected: { classPropertyName: "selected", publicName: "selected", isSignal: true, isRequired: false, transformFunction: null }, size: { classPropertyName: "size", publicName: "size", isSignal: true, isRequired: false, transformFunction: null }, tabindex: { classPropertyName: "tabindex", publicName: "tabindex", isSignal: true, isRequired: false, transformFunction: null }, type: { classPropertyName: "type", publicName: "type", isSignal: true, isRequired: false, transformFunction: null }, toggleable: { classPropertyName: "toggleable", publicName: "toggleable", isSignal: true, isRequired: false, transformFunction: null }, userClass: { classPropertyName: "userClass", publicName: "class", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { disabled: "disabledChange", loading: "loadingChange", look: "lookChange", selected: "selectedChange" }, host: { properties: { "attr.aria-busy": "loading() ? 'true' : undefined", "attr.aria-disabled": "effectiveDisabled() || loading() ? 'true' : undefined", "attr.aria-haspopup": "ariaHasPopup() !== 'false' ? ariaHasPopup() : null", "attr.aria-pressed": "displaysPressedState() ? (selected() ? 'true' : 'false') : undefined", "attr.data-look": "effectiveLook()", "attr.data-size": "effectiveSize()", "attr.disabled": "effectiveDisabled() || loading() ? '' : undefined", "attr.tabindex": "effectiveDisabled() || loading() ? -1 : tabindex()", "attr.type": "type()", "class": "baseClass()" } }, ngImport: i0 }); }
536
+ static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "22.0.6", type: ButtonDirective, isStandalone: true, selector: "button[monaButton]", inputs: { ariaHasPopup: { classPropertyName: "ariaHasPopup", publicName: "aria-haspopup", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, iconOnly: { classPropertyName: "iconOnly", publicName: "iconOnly", isSignal: true, isRequired: false, transformFunction: null }, loading: { classPropertyName: "loading", publicName: "loading", isSignal: true, isRequired: false, transformFunction: null }, look: { classPropertyName: "look", publicName: "look", isSignal: true, isRequired: false, transformFunction: null }, rounded: { classPropertyName: "rounded", publicName: "rounded", isSignal: true, isRequired: false, transformFunction: null }, selected: { classPropertyName: "selected", publicName: "selected", isSignal: true, isRequired: false, transformFunction: null }, size: { classPropertyName: "size", publicName: "size", isSignal: true, isRequired: false, transformFunction: null }, tabindex: { classPropertyName: "tabindex", publicName: "tabindex", isSignal: true, isRequired: false, transformFunction: null }, toggleable: { classPropertyName: "toggleable", publicName: "toggleable", isSignal: true, isRequired: false, transformFunction: null }, type: { classPropertyName: "type", publicName: "type", isSignal: true, isRequired: false, transformFunction: null }, userClass: { classPropertyName: "userClass", publicName: "class", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { look: "lookChange", selected: "selectedChange" }, host: { properties: { "attr.aria-busy": "loading() ? 'true' : undefined", "attr.aria-disabled": "effectiveDisabled() || loading() ? 'true' : undefined", "attr.aria-haspopup": "ariaHasPopup() !== 'false' ? ariaHasPopup() : null", "attr.aria-pressed": "effectiveToggleable() ? (selected() ? 'true' : 'false') : undefined", "attr.data-look": "effectiveLook()", "attr.data-size": "effectiveSize()", "attr.disabled": "effectiveDisabled() ? '' : undefined", "attr.tabindex": "effectiveDisabled() ? -1 : tabindex()", "attr.type": "type()", "class": "baseClass()" } }, ngImport: i0 }); }
475
537
  }
476
538
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.6", ngImport: i0, type: ButtonDirective, decorators: [{
477
539
  type: Directive,
@@ -481,16 +543,16 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.6", ngImpor
481
543
  "[attr.aria-busy]": "loading() ? 'true' : undefined",
482
544
  "[attr.aria-disabled]": "effectiveDisabled() || loading() ? 'true' : undefined",
483
545
  "[attr.aria-haspopup]": "ariaHasPopup() !== 'false' ? ariaHasPopup() : null",
484
- "[attr.aria-pressed]": "displaysPressedState() ? (selected() ? 'true' : 'false') : undefined",
546
+ "[attr.aria-pressed]": "effectiveToggleable() ? (selected() ? 'true' : 'false') : undefined",
485
547
  "[attr.data-look]": "effectiveLook()",
486
548
  "[attr.data-size]": "effectiveSize()",
487
- "[attr.disabled]": "effectiveDisabled() || loading() ? '' : undefined",
488
- "[attr.tabindex]": "effectiveDisabled() || loading() ? -1 : tabindex()",
549
+ "[attr.disabled]": "effectiveDisabled() ? '' : undefined",
550
+ "[attr.tabindex]": "effectiveDisabled() ? -1 : tabindex()",
489
551
  "[attr.type]": "type()",
490
552
  "[class]": "baseClass()"
491
553
  }
492
554
  }]
493
- }], ctorParameters: () => [], propDecorators: { ariaHasPopup: [{ type: i0.Input, args: [{ isSignal: true, alias: "aria-haspopup", required: false }] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }, { type: i0.Output, args: ["disabledChange"] }], iconOnly: [{ type: i0.Input, args: [{ isSignal: true, alias: "iconOnly", required: false }] }], loading: [{ type: i0.Input, args: [{ isSignal: true, alias: "loading", required: false }] }, { type: i0.Output, args: ["loadingChange"] }], look: [{ type: i0.Input, args: [{ isSignal: true, alias: "look", required: false }] }, { type: i0.Output, args: ["lookChange"] }], rounded: [{ type: i0.Input, args: [{ isSignal: true, alias: "rounded", required: false }] }], selected: [{ type: i0.Input, args: [{ isSignal: true, alias: "selected", required: false }] }, { type: i0.Output, args: ["selectedChange"] }], size: [{ type: i0.Input, args: [{ isSignal: true, alias: "size", required: false }] }], tabindex: [{ type: i0.Input, args: [{ isSignal: true, alias: "tabindex", required: false }] }], type: [{ type: i0.Input, args: [{ isSignal: true, alias: "type", required: false }] }], toggleable: [{ type: i0.Input, args: [{ isSignal: true, alias: "toggleable", required: false }] }], userClass: [{ type: i0.Input, args: [{ isSignal: true, alias: "class", required: false }] }] } });
555
+ }], ctorParameters: () => [], propDecorators: { ariaHasPopup: [{ type: i0.Input, args: [{ isSignal: true, alias: "aria-haspopup", required: false }] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }], iconOnly: [{ type: i0.Input, args: [{ isSignal: true, alias: "iconOnly", required: false }] }], loading: [{ type: i0.Input, args: [{ isSignal: true, alias: "loading", required: false }] }], look: [{ type: i0.Input, args: [{ isSignal: true, alias: "look", required: false }] }, { type: i0.Output, args: ["lookChange"] }], rounded: [{ type: i0.Input, args: [{ isSignal: true, alias: "rounded", required: false }] }], selected: [{ type: i0.Input, args: [{ isSignal: true, alias: "selected", required: false }] }, { type: i0.Output, args: ["selectedChange"] }], size: [{ type: i0.Input, args: [{ isSignal: true, alias: "size", required: false }] }], tabindex: [{ type: i0.Input, args: [{ isSignal: true, alias: "tabindex", required: false }] }], toggleable: [{ type: i0.Input, args: [{ isSignal: true, alias: "toggleable", required: false }] }], type: [{ type: i0.Input, args: [{ isSignal: true, alias: "type", required: false }] }], userClass: [{ type: i0.Input, args: [{ isSignal: true, alias: "class", required: false }] }] } });
494
556
 
495
557
  /*
496
558
  * Public API Surface of @nanahoshi/mona-ui/button
@@ -111,7 +111,6 @@ const calendarHeaderThemeVariants = cva(`
111
111
  [&>button:nth-of-type(3)]:rounded-ee-none
112
112
  [&>button:nth-of-type(4)]:rounded-ss-none
113
113
  [&>button:nth-of-type(4)]:rounded-es-none
114
- [&>button]:outline-none
115
114
  `);
116
115
  const calendarMonthViewDayThemeVariants = cva(`
117
116
  cursor-pointer
@@ -1537,7 +1536,7 @@ class CalendarComponent {
1537
1536
  }
1538
1537
  }
1539
1538
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.6", ngImport: i0, type: CalendarComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
1540
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.0.6", type: CalendarComponent, isStandalone: true, selector: "mona-calendar", inputs: { disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, disabledDates: { classPropertyName: "disabledDates", publicName: "disabledDates", isSignal: true, isRequired: false, transformFunction: null }, firstDay: { classPropertyName: "firstDay", publicName: "firstDay", isSignal: true, isRequired: false, transformFunction: null }, invalid: { classPropertyName: "invalid", publicName: "invalid", isSignal: true, isRequired: false, transformFunction: null }, maxDate: { classPropertyName: "maxDate", publicName: "maxDate", isSignal: true, isRequired: false, transformFunction: null }, minDate: { classPropertyName: "minDate", publicName: "minDate", isSignal: true, isRequired: false, transformFunction: null }, readonly: { classPropertyName: "readonly", publicName: "readonly", isSignal: true, isRequired: false, transformFunction: null }, required: { classPropertyName: "required", publicName: "required", isSignal: true, isRequired: false, transformFunction: null }, rounded: { classPropertyName: "rounded", publicName: "rounded", isSignal: true, isRequired: false, transformFunction: null }, selection: { classPropertyName: "selection", publicName: "selection", isSignal: true, isRequired: false, transformFunction: null }, touched: { classPropertyName: "touched", publicName: "touched", isSignal: true, isRequired: false, transformFunction: null }, userClass: { classPropertyName: "userClass", publicName: "class", isSignal: true, isRequired: false, transformFunction: null }, value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: false, transformFunction: null }, weekNumber: { classPropertyName: "weekNumber", publicName: "weekNumber", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { disabled: "disabledChange", touch: "touch", value: "valueChange" }, host: { attributes: { "role": "application" }, properties: { "attr.aria-label": "ariaLabel()", "attr.aria-invalid": "invalidState() ? 'true' : null", "attr.data-invalid": "invalidState() || null", "attr.data-required": "required() || null", "attr.tabindex": "disabled() ? -1 : 0", "class": "baseClass()" } }, queries: [{ propertyName: "decadeCellTemplate", first: true, predicate: CalendarDecadeCellTemplateDirective, descendants: true, isSignal: true }, { propertyName: "monthCellTemplate", first: true, predicate: CalendarMonthCellTemplateDirective, descendants: true, isSignal: true }, { propertyName: "yearCellTemplate", first: true, predicate: CalendarYearCellTemplateDirective, descendants: true, isSignal: true }], ngImport: i0, template: "<div [class]=\"headerClass()\">\n <button\n monaButton\n look=\"ghost\"\n [rounded]=\"rounded()\"\n [size]=\"'small'\"\n (click)=\"onTodayButtonClick()\"\n [attr.aria-label]=\"todayButtonLabel()\">\n <span>{{ messages().today }}</span>\n </button>\n @switch (calendarView()) {\n @case (\"month\") {\n <button\n monaButton\n look=\"ghost\"\n [rounded]=\"rounded()\"\n (click)=\"onViewChangeClick('year')\"\n [attr.aria-label]=\"viewSwitchButtonLabel()\">\n <span class=\"text-primary font-semibold\" [id]=\"gridId + '-heading'\">{{\n headerMonthYear()\n }}</span>\n </button>\n }\n @case (\"year\") {\n <button\n monaButton\n look=\"ghost\"\n [rounded]=\"rounded()\"\n (click)=\"onViewChangeClick('decade')\"\n [attr.aria-label]=\"viewSwitchButtonLabel()\">\n <span class=\"text-primary font-semibold\" [id]=\"gridId + '-heading'\">{{\n headerYear()\n }}</span>\n </button>\n }\n @case (\"decade\") {\n <button monaButton look=\"ghost\" [rounded]=\"rounded()\" [attr.aria-label]=\"viewSwitchButtonLabel()\">\n <span class=\"text-primary font-semibold\" [id]=\"gridId + '-heading'\"\n >{{ formatInteger(decadeStart()) }} - {{ formatInteger(decadeEnd()) }}</span\n >\n </button>\n }\n }\n <button\n monaButton\n look=\"ghost\"\n [rounded]=\"rounded()\"\n [iconOnly]=\"true\"\n [size]=\"'small'\"\n (click)=\"onNavigationClick('prev')\"\n [attr.aria-label]=\"prevButtonLabel()\">\n <svg lucideChevronLeft class=\"rtl:rotate-180\"></svg>\n </button>\n <button\n monaButton\n look=\"ghost\"\n [rounded]=\"rounded()\"\n [iconOnly]=\"true\"\n [size]=\"'small'\"\n (click)=\"onNavigationClick('next')\"\n [attr.aria-label]=\"nextButtonLabel()\">\n <svg lucideChevronRight class=\"rtl:rotate-180\"></svg>\n </button>\n</div>\n\n<div aria-live=\"polite\" aria-atomic=\"true\" class=\"sr-only\">{{ ariaLabel() }}</div>\n\n@if (calendarView() === \"month\") {\n @let columnCount = weekNumber() ? 8 : 7;\n <div [class]=\"monthGridHeaderClass()\" [style.grid-template-columns]=\"`repeat(${columnCount}, 32px)`\">\n @if (weekNumber()) {\n <div></div>\n }\n @for (day of weekdays(); track day.full) {\n <div>\n <span aria-hidden=\"true\">{{ day.display }}</span>\n <span class=\"sr-only\">{{ day.full }}</span>\n </div>\n }\n </div>\n <div\n [class]=\"monthGridClass()\"\n [attr.aria-labelledby]=\"gridId + '-heading'\"\n (pointerleave)=\"onMonthGridPointerLeave()\"\n [style.grid-template-columns]=\"`repeat(${columnCount}, 32px)`\">\n @for (row of monthDictChunked(); track $index) {\n @if (weekNumber()) {\n @let firstEntry = row | monaTakeFirst;\n @if (firstEntry) {\n @let week = getWeekNumber(firstEntry.key);\n <div>{{ formatInteger(week) }}</div>\n }\n }\n @for (entry of row; track entry.key) {\n <div\n (dayPointerEnter)=\"onDayPointerEnter($event)\"\n (daySelect)=\"onDayClick($event.date, $event.event)\"\n monaMonthDay\n [disabled]=\"disabled()\"\n [disabledDates]=\"disabledDates()\"\n [min]=\"minDate()\"\n [max]=\"maxDate()\"\n [monthBounds]=\"[monthBounds().start, monthBounds().end]\"\n [navigatedDate]=\"navigatedDate()\"\n [rangePreview]=\"rangePreviewDates()\"\n [rounded]=\"rounded()\"\n [value]=\"selectedDates()\"\n [entry]=\"entry\">\n @if (monthCellTemplate()) {\n <ng-container\n [ngTemplateOutlet]=\"monthCellTemplate()?.templateRef\"\n [ngTemplateOutletContext]=\"{ $implicit: entry.value, date: entry.key }\"></ng-container>\n } @else {\n <span>{{ formatInteger(entry.value) }}</span>\n }\n </div>\n }\n }\n </div>\n} @else if (calendarView() === \"year\") {\n <div [class]=\"yearGridClass()\" [attr.aria-labelledby]=\"gridId + '-heading'\">\n @for (row of months(); track $index) {\n @for (monthItem of row; track monthItem) {\n <div\n (click)=\"onMonthClick(monthItem[0])\"\n monaYearMonth\n [month]=\"monthItem[0]\"\n [monthName]=\"monthItem[1]\"\n [navigatedDate]=\"navigatedDate()\"\n [rounded]=\"rounded()\"\n [selectedDate]=\"selectedDates()[0]\">\n @if (yearCellTemplate()) {\n <ng-container\n [ngTemplateOutlet]=\"yearCellTemplate()?.templateRef\"\n [ngTemplateOutletContext]=\"{ $implicit: monthItem[0], text: monthItem[1] }\">\n </ng-container>\n } @else {\n <span>{{ monthItem[1] }}</span>\n }\n </div>\n }\n }\n </div>\n} @else if (calendarView() === \"decade\") {\n <div [class]=\"decadeGridClass()\" [attr.aria-labelledby]=\"gridId + '-heading'\">\n @for (row of decadeYears(); track $index) {\n @for (year of row; track year) {\n <div\n (click)=\"onYearClick(year)\"\n monaDecadeYear\n [navigatedDate]=\"navigatedDate()\"\n [rounded]=\"rounded()\"\n [year]=\"year\"\n [selectedDate]=\"selectedDates()[0]\">\n @if (decadeCellTemplate()) {\n <ng-container\n [ngTemplateOutlet]=\"decadeCellTemplate()?.templateRef\"\n [ngTemplateOutletContext]=\"{ $implicit: year }\">\n </ng-container>\n } @else {\n <span>{{ formatInteger(year) }}</span>\n }\n </div>\n }\n }\n </div>\n}\n", dependencies: [{ kind: "directive", type: ButtonDirective, selector: "button[monaButton]", inputs: ["aria-haspopup", "disabled", "iconOnly", "loading", "look", "rounded", "selected", "size", "tabindex", "type", "toggleable", "class"], outputs: ["disabledChange", "loadingChange", "lookChange", "selectedChange"] }, { kind: "directive", type: MonthDayDirective, selector: "[monaMonthDay]", inputs: ["disabled", "disabledDates", "entry", "max", "min", "monthBounds", "navigatedDate", "rangePreview", "rounded", "value"], outputs: ["dayPointerEnter", "daySelect"] }, { kind: "directive", type: DecadeYearDirective, selector: "[monaDecadeYear]", inputs: ["navigatedDate", "rounded", "selectedDate", "year"] }, { kind: "directive", type: YearMonthDirective, selector: "[monaYearMonth]", inputs: ["month", "monthName", "navigatedDate", "rounded", "selectedDate"] }, { kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "component", type: LucideChevronLeft, selector: "svg[lucideChevronLeft]" }, { kind: "component", type: LucideChevronRight, selector: "svg[lucideChevronRight]" }, { kind: "pipe", type: TakeFirstPipe, name: "monaTakeFirst" }] }); }
1539
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.0.6", type: CalendarComponent, isStandalone: true, selector: "mona-calendar", inputs: { disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, disabledDates: { classPropertyName: "disabledDates", publicName: "disabledDates", isSignal: true, isRequired: false, transformFunction: null }, firstDay: { classPropertyName: "firstDay", publicName: "firstDay", isSignal: true, isRequired: false, transformFunction: null }, invalid: { classPropertyName: "invalid", publicName: "invalid", isSignal: true, isRequired: false, transformFunction: null }, maxDate: { classPropertyName: "maxDate", publicName: "maxDate", isSignal: true, isRequired: false, transformFunction: null }, minDate: { classPropertyName: "minDate", publicName: "minDate", isSignal: true, isRequired: false, transformFunction: null }, readonly: { classPropertyName: "readonly", publicName: "readonly", isSignal: true, isRequired: false, transformFunction: null }, required: { classPropertyName: "required", publicName: "required", isSignal: true, isRequired: false, transformFunction: null }, rounded: { classPropertyName: "rounded", publicName: "rounded", isSignal: true, isRequired: false, transformFunction: null }, selection: { classPropertyName: "selection", publicName: "selection", isSignal: true, isRequired: false, transformFunction: null }, touched: { classPropertyName: "touched", publicName: "touched", isSignal: true, isRequired: false, transformFunction: null }, userClass: { classPropertyName: "userClass", publicName: "class", isSignal: true, isRequired: false, transformFunction: null }, value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: false, transformFunction: null }, weekNumber: { classPropertyName: "weekNumber", publicName: "weekNumber", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { disabled: "disabledChange", touch: "touch", value: "valueChange" }, host: { attributes: { "role": "application" }, properties: { "attr.aria-label": "ariaLabel()", "attr.aria-invalid": "invalidState() ? 'true' : null", "attr.data-invalid": "invalidState() || null", "attr.data-required": "required() || null", "attr.tabindex": "disabled() ? -1 : 0", "class": "baseClass()" } }, queries: [{ propertyName: "decadeCellTemplate", first: true, predicate: CalendarDecadeCellTemplateDirective, descendants: true, isSignal: true }, { propertyName: "monthCellTemplate", first: true, predicate: CalendarMonthCellTemplateDirective, descendants: true, isSignal: true }, { propertyName: "yearCellTemplate", first: true, predicate: CalendarYearCellTemplateDirective, descendants: true, isSignal: true }], ngImport: i0, template: "<div [class]=\"headerClass()\">\n <button\n monaButton\n look=\"ghost\"\n [rounded]=\"rounded()\"\n [size]=\"'small'\"\n (click)=\"onTodayButtonClick()\"\n [attr.aria-label]=\"todayButtonLabel()\">\n <span>{{ messages().today }}</span>\n </button>\n @switch (calendarView()) {\n @case (\"month\") {\n <button\n monaButton\n look=\"ghost\"\n [rounded]=\"rounded()\"\n (click)=\"onViewChangeClick('year')\"\n [attr.aria-label]=\"viewSwitchButtonLabel()\">\n <span class=\"text-primary font-semibold\" [id]=\"gridId + '-heading'\">{{\n headerMonthYear()\n }}</span>\n </button>\n }\n @case (\"year\") {\n <button\n monaButton\n look=\"ghost\"\n [rounded]=\"rounded()\"\n (click)=\"onViewChangeClick('decade')\"\n [attr.aria-label]=\"viewSwitchButtonLabel()\">\n <span class=\"text-primary font-semibold\" [id]=\"gridId + '-heading'\">{{\n headerYear()\n }}</span>\n </button>\n }\n @case (\"decade\") {\n <button monaButton look=\"ghost\" [rounded]=\"rounded()\" [attr.aria-label]=\"viewSwitchButtonLabel()\">\n <span class=\"text-primary font-semibold\" [id]=\"gridId + '-heading'\"\n >{{ formatInteger(decadeStart()) }} - {{ formatInteger(decadeEnd()) }}</span\n >\n </button>\n }\n }\n <button\n monaButton\n look=\"ghost\"\n [rounded]=\"rounded()\"\n [iconOnly]=\"true\"\n [size]=\"'small'\"\n (click)=\"onNavigationClick('prev')\"\n [attr.aria-label]=\"prevButtonLabel()\">\n <svg lucideChevronLeft class=\"rtl:rotate-180\"></svg>\n </button>\n <button\n monaButton\n look=\"ghost\"\n [rounded]=\"rounded()\"\n [iconOnly]=\"true\"\n [size]=\"'small'\"\n (click)=\"onNavigationClick('next')\"\n [attr.aria-label]=\"nextButtonLabel()\">\n <svg lucideChevronRight class=\"rtl:rotate-180\"></svg>\n </button>\n</div>\n\n<div aria-live=\"polite\" aria-atomic=\"true\" class=\"sr-only\">{{ ariaLabel() }}</div>\n\n@if (calendarView() === \"month\") {\n @let columnCount = weekNumber() ? 8 : 7;\n <div [class]=\"monthGridHeaderClass()\" [style.grid-template-columns]=\"`repeat(${columnCount}, 32px)`\">\n @if (weekNumber()) {\n <div></div>\n }\n @for (day of weekdays(); track day.full) {\n <div>\n <span aria-hidden=\"true\">{{ day.display }}</span>\n <span class=\"sr-only\">{{ day.full }}</span>\n </div>\n }\n </div>\n <div\n [class]=\"monthGridClass()\"\n [attr.aria-labelledby]=\"gridId + '-heading'\"\n (pointerleave)=\"onMonthGridPointerLeave()\"\n [style.grid-template-columns]=\"`repeat(${columnCount}, 32px)`\">\n @for (row of monthDictChunked(); track $index) {\n @if (weekNumber()) {\n @let firstEntry = row | monaTakeFirst;\n @if (firstEntry) {\n @let week = getWeekNumber(firstEntry.key);\n <div>{{ formatInteger(week) }}</div>\n }\n }\n @for (entry of row; track entry.key) {\n <div\n (dayPointerEnter)=\"onDayPointerEnter($event)\"\n (daySelect)=\"onDayClick($event.date, $event.event)\"\n monaMonthDay\n [disabled]=\"disabled()\"\n [disabledDates]=\"disabledDates()\"\n [min]=\"minDate()\"\n [max]=\"maxDate()\"\n [monthBounds]=\"[monthBounds().start, monthBounds().end]\"\n [navigatedDate]=\"navigatedDate()\"\n [rangePreview]=\"rangePreviewDates()\"\n [rounded]=\"rounded()\"\n [value]=\"selectedDates()\"\n [entry]=\"entry\">\n @if (monthCellTemplate()) {\n <ng-container\n [ngTemplateOutlet]=\"monthCellTemplate()?.templateRef\"\n [ngTemplateOutletContext]=\"{ $implicit: entry.value, date: entry.key }\"></ng-container>\n } @else {\n <span>{{ formatInteger(entry.value) }}</span>\n }\n </div>\n }\n }\n </div>\n} @else if (calendarView() === \"year\") {\n <div [class]=\"yearGridClass()\" [attr.aria-labelledby]=\"gridId + '-heading'\">\n @for (row of months(); track $index) {\n @for (monthItem of row; track monthItem) {\n <div\n (click)=\"onMonthClick(monthItem[0])\"\n monaYearMonth\n [month]=\"monthItem[0]\"\n [monthName]=\"monthItem[1]\"\n [navigatedDate]=\"navigatedDate()\"\n [rounded]=\"rounded()\"\n [selectedDate]=\"selectedDates()[0]\">\n @if (yearCellTemplate()) {\n <ng-container\n [ngTemplateOutlet]=\"yearCellTemplate()?.templateRef\"\n [ngTemplateOutletContext]=\"{ $implicit: monthItem[0], text: monthItem[1] }\">\n </ng-container>\n } @else {\n <span>{{ monthItem[1] }}</span>\n }\n </div>\n }\n }\n </div>\n} @else if (calendarView() === \"decade\") {\n <div [class]=\"decadeGridClass()\" [attr.aria-labelledby]=\"gridId + '-heading'\">\n @for (row of decadeYears(); track $index) {\n @for (year of row; track year) {\n <div\n (click)=\"onYearClick(year)\"\n monaDecadeYear\n [navigatedDate]=\"navigatedDate()\"\n [rounded]=\"rounded()\"\n [year]=\"year\"\n [selectedDate]=\"selectedDates()[0]\">\n @if (decadeCellTemplate()) {\n <ng-container\n [ngTemplateOutlet]=\"decadeCellTemplate()?.templateRef\"\n [ngTemplateOutletContext]=\"{ $implicit: year }\">\n </ng-container>\n } @else {\n <span>{{ formatInteger(year) }}</span>\n }\n </div>\n }\n }\n </div>\n}\n", dependencies: [{ kind: "directive", type: ButtonDirective, selector: "button[monaButton]", inputs: ["aria-haspopup", "disabled", "iconOnly", "loading", "look", "rounded", "selected", "size", "tabindex", "toggleable", "type", "class"], outputs: ["lookChange", "selectedChange"] }, { kind: "directive", type: MonthDayDirective, selector: "[monaMonthDay]", inputs: ["disabled", "disabledDates", "entry", "max", "min", "monthBounds", "navigatedDate", "rangePreview", "rounded", "value"], outputs: ["dayPointerEnter", "daySelect"] }, { kind: "directive", type: DecadeYearDirective, selector: "[monaDecadeYear]", inputs: ["navigatedDate", "rounded", "selectedDate", "year"] }, { kind: "directive", type: YearMonthDirective, selector: "[monaYearMonth]", inputs: ["month", "monthName", "navigatedDate", "rounded", "selectedDate"] }, { kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "component", type: LucideChevronLeft, selector: "svg[lucideChevronLeft]" }, { kind: "component", type: LucideChevronRight, selector: "svg[lucideChevronRight]" }, { kind: "pipe", type: TakeFirstPipe, name: "monaTakeFirst" }] }); }
1541
1540
  }
1542
1541
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.6", ngImport: i0, type: CalendarComponent, decorators: [{
1543
1542
  type: Component,
@@ -542,7 +542,7 @@ class ChipComponent {
542
542
  });
543
543
  }
544
544
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.6", ngImport: i0, type: ChipComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
545
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.0.6", type: ChipComponent, isStandalone: true, selector: "mona-chip", inputs: { ariaLabel: { classPropertyName: "ariaLabel", publicName: "aria-label", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, label: { classPropertyName: "label", publicName: "label", isSignal: true, isRequired: false, transformFunction: null }, look: { classPropertyName: "look", publicName: "look", isSignal: true, isRequired: false, transformFunction: null }, removable: { classPropertyName: "removable", publicName: "removable", isSignal: true, isRequired: false, transformFunction: null }, removeLabel: { classPropertyName: "removeLabel", publicName: "removeLabel", isSignal: true, isRequired: false, transformFunction: null }, removeTabIndex: { classPropertyName: "removeTabIndex", publicName: "removeTabIndex", isSignal: true, isRequired: false, transformFunction: null }, rounded: { classPropertyName: "rounded", publicName: "rounded", isSignal: true, isRequired: false, transformFunction: null }, selected: { classPropertyName: "selected", publicName: "selected", isSignal: true, isRequired: false, transformFunction: null }, size: { classPropertyName: "size", publicName: "size", isSignal: true, isRequired: false, transformFunction: null }, tabindex: { classPropertyName: "tabindex", publicName: "tabindex", isSignal: true, isRequired: false, transformFunction: null }, toggleable: { classPropertyName: "toggleable", publicName: "toggleable", isSignal: true, isRequired: false, transformFunction: null }, userClass: { classPropertyName: "userClass", publicName: "class", isSignal: true, isRequired: false, transformFunction: null }, value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { contentClick: "contentClick", remove: "remove", selected: "selectedChange" }, host: { properties: { "class": "baseClass()", "attr.tabindex": "effectiveTabIndex()", "attr.aria-disabled": "disabled() ? 'true' : undefined", "attr.role": "role()", "attr.aria-checked": "ariaChecked()", "attr.aria-label": "effectiveAriaLabel()" } }, queries: [{ propertyName: "prefixTemplate", first: true, predicate: ChipPrefixTemplateDirective, descendants: true, read: TemplateRef, isSignal: true }], ngImport: i0, template: "@if (prefixTemplate()) {\n <ng-container [ngTemplateOutlet]=\"prefixTemplate()\"></ng-container>\n}\n\n@if (label()) {\n <span>{{ label() }}</span>\n} @else {\n <ng-content></ng-content>\n}\n\n@if (removable()) {\n @let removeAriaLabel = removeLabel() ?? messages().removeLabel(label());\n <button\n monaButton\n look=\"link\"\n [iconOnly]=\"true\"\n [size]=\"'small'\"\n [attr.aria-label]=\"removeAriaLabel\"\n [tabindex]=\"removeTabIndex()\"\n [disabled]=\"disabled()\"\n (click)=\"onRemoveClick($event)\"\n [attr.data-chip-remove]=\"true\">\n <svg lucideCircleX [size]=\"iconSize()\"></svg>\n </button>\n}\n", dependencies: [{ kind: "directive", type: ButtonDirective, selector: "button[monaButton]", inputs: ["aria-haspopup", "disabled", "iconOnly", "loading", "look", "rounded", "selected", "size", "tabindex", "type", "toggleable", "class"], outputs: ["disabledChange", "loadingChange", "lookChange", "selectedChange"] }, { kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "component", type: LucideCircleX, selector: "svg[lucideCircleX], svg[lucideXCircle]" }] }); }
545
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.0.6", type: ChipComponent, isStandalone: true, selector: "mona-chip", inputs: { ariaLabel: { classPropertyName: "ariaLabel", publicName: "aria-label", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, label: { classPropertyName: "label", publicName: "label", isSignal: true, isRequired: false, transformFunction: null }, look: { classPropertyName: "look", publicName: "look", isSignal: true, isRequired: false, transformFunction: null }, removable: { classPropertyName: "removable", publicName: "removable", isSignal: true, isRequired: false, transformFunction: null }, removeLabel: { classPropertyName: "removeLabel", publicName: "removeLabel", isSignal: true, isRequired: false, transformFunction: null }, removeTabIndex: { classPropertyName: "removeTabIndex", publicName: "removeTabIndex", isSignal: true, isRequired: false, transformFunction: null }, rounded: { classPropertyName: "rounded", publicName: "rounded", isSignal: true, isRequired: false, transformFunction: null }, selected: { classPropertyName: "selected", publicName: "selected", isSignal: true, isRequired: false, transformFunction: null }, size: { classPropertyName: "size", publicName: "size", isSignal: true, isRequired: false, transformFunction: null }, tabindex: { classPropertyName: "tabindex", publicName: "tabindex", isSignal: true, isRequired: false, transformFunction: null }, toggleable: { classPropertyName: "toggleable", publicName: "toggleable", isSignal: true, isRequired: false, transformFunction: null }, userClass: { classPropertyName: "userClass", publicName: "class", isSignal: true, isRequired: false, transformFunction: null }, value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { contentClick: "contentClick", remove: "remove", selected: "selectedChange" }, host: { properties: { "class": "baseClass()", "attr.tabindex": "effectiveTabIndex()", "attr.aria-disabled": "disabled() ? 'true' : undefined", "attr.role": "role()", "attr.aria-checked": "ariaChecked()", "attr.aria-label": "effectiveAriaLabel()" } }, queries: [{ propertyName: "prefixTemplate", first: true, predicate: ChipPrefixTemplateDirective, descendants: true, read: TemplateRef, isSignal: true }], ngImport: i0, template: "@if (prefixTemplate()) {\n <ng-container [ngTemplateOutlet]=\"prefixTemplate()\"></ng-container>\n}\n\n@if (label()) {\n <span>{{ label() }}</span>\n} @else {\n <ng-content></ng-content>\n}\n\n@if (removable()) {\n @let removeAriaLabel = removeLabel() ?? messages().removeLabel(label());\n <button\n monaButton\n look=\"link\"\n [iconOnly]=\"true\"\n [size]=\"'small'\"\n [attr.aria-label]=\"removeAriaLabel\"\n [tabindex]=\"removeTabIndex()\"\n [disabled]=\"disabled()\"\n (click)=\"onRemoveClick($event)\"\n [attr.data-chip-remove]=\"true\">\n <svg lucideCircleX [size]=\"iconSize()\"></svg>\n </button>\n}\n", dependencies: [{ kind: "directive", type: ButtonDirective, selector: "button[monaButton]", inputs: ["aria-haspopup", "disabled", "iconOnly", "loading", "look", "rounded", "selected", "size", "tabindex", "toggleable", "type", "class"], outputs: ["lookChange", "selectedChange"] }, { kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "component", type: LucideCircleX, selector: "svg[lucideCircleX], svg[lucideXCircle]" }] }); }
546
546
  }
547
547
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.6", ngImport: i0, type: ChipComponent, decorators: [{
548
548
  type: Component,
@@ -789,7 +789,7 @@ class ColorGradientComponent {
789
789
  }
790
790
  }
791
791
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.6", ngImport: i0, type: ColorGradientComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
792
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.0.6", type: ColorGradientComponent, isStandalone: true, selector: "mona-color-gradient", inputs: { disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, format: { classPropertyName: "format", publicName: "format", isSignal: true, isRequired: false, transformFunction: null }, invalid: { classPropertyName: "invalid", publicName: "invalid", isSignal: true, isRequired: false, transformFunction: null }, opacity: { classPropertyName: "opacity", publicName: "opacity", isSignal: true, isRequired: false, transformFunction: null }, required: { classPropertyName: "required", publicName: "required", isSignal: true, isRequired: false, transformFunction: null }, rounded: { classPropertyName: "rounded", publicName: "rounded", isSignal: true, isRequired: false, transformFunction: null }, showButtons: { classPropertyName: "showButtons", publicName: "showButtons", isSignal: true, isRequired: false, transformFunction: null }, showHexInput: { classPropertyName: "showHexInput", publicName: "showHexInput", isSignal: true, isRequired: false, transformFunction: null }, showColorInputs: { classPropertyName: "showColorInputs", publicName: "showColorInputs", isSignal: true, isRequired: false, transformFunction: null }, touched: { classPropertyName: "touched", publicName: "touched", isSignal: true, isRequired: false, transformFunction: null }, value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { apply: "apply", cancel: "cancel", touch: "touch", value: "valueChange" }, host: { properties: { "class": "baseClasses()", "attr.data-disabled": "disabled()", "attr.data-invalid": "invalidState() || null", "attr.aria-invalid": "invalidState() ? 'true' : null" } }, viewQueries: [{ propertyName: "hsvHandle", first: true, predicate: ["hsvPointer"], descendants: true, isSignal: true }, { propertyName: "hsvRectangle", first: true, predicate: ["hsvRectangle"], descendants: true, isSignal: true }], ngImport: i0, template: "<div [class]=\"hsvRectangleClasses()\" [style.background-color]=\"hsvRectangleBackground()\" #hsvRectangle>\n <div\n [class]=\"hsvRectangleHandleClasses()\"\n [style.left.px]=\"hsvHandleLeft()\"\n [style.top.px]=\"hsvHandleTop()\"\n [attr.tabindex]=\"disabled() ? -1 : 0\"\n [attr.role]=\"'slider'\"\n [attr.aria-label]=\"messages().saturationAndValue\"\n [attr.aria-valuemin]=\"0\"\n [attr.aria-valuemax]=\"100\"\n [attr.aria-valuenow]=\"hsv().s\"\n [attr.aria-valuetext]=\"messages().saturationAndValueText(hsv().s ?? 0, hsv().v ?? 0)\"\n [attr.aria-disabled]=\"disabled() || null\"\n (keydown)=\"onHsvHandleKeyDown($event)\"\n (blur)=\"onHsvHandleBlur()\"\n #hsvPointer></div>\n</div>\n<div class=\"flex items-center gap-2\">\n <div class=\"flex flex-1 flex-col gap-1 me-2\">\n <mona-slider\n [minValue]=\"0\"\n [maxValue]=\"360\"\n [trackBackground]=\"'linear-gradient(to right, #ff0000, #ffff00, #00ff00, #00ffff, #0000ff, #ff00ff, #ff0000)'\"\n [selectionBackground]=\"'transparent'\"\n [handleClasses]=\"sliderHandleClasses()\"\n [trackSize]=\"sliderHeight\"\n [rounded]=\"rounded()\"\n [value]=\"hsv().h ?? 0\"\n (valueChange)=\"hueValue$.next($event)\"\n (touch)=\"onSliderBlur()\"></mona-slider>\n @if (opacity()) {\n <mona-slider\n [minValue]=\"0\"\n [maxValue]=\"255\"\n [trackBackground]=\"alphaSliderBackground()\"\n [selectionBackground]=\"'transparent'\"\n [handleClasses]=\"sliderHandleClasses()\"\n [trackSize]=\"sliderHeight\"\n [rounded]=\"rounded()\"\n [value]=\"alpha()\"\n (valueChange)=\"onAlphaChange($event)\"\n (touch)=\"onSliderBlur()\"></mona-slider>\n }\n </div>\n @for (preview of colorPreviews(); track preview.type) {\n <div\n [class]=\"colorPreviewClasses()\"\n [class.cursor-pointer]=\"$index === 1\"\n [style.background-color]=\"preview.color\"\n [attr.title]=\"$index === 1 ? preview.title : null\"\n [attr.aria-label]=\"$index === 1 ? preview.title : null\"\n [attr.aria-hidden]=\"$index === 0 ? 'true' : null\"\n [attr.role]=\"$index === 1 ? 'button' : null\"\n [attr.tabindex]=\"$index === 1 ? 0 : null\"\n (click)=\"preview.onClick?.()\"\n (keydown)=\"onPreviousColorKeyDown($event, preview.onClick)\"></div>\n }\n <button monaButton look=\"ghost\" size=\"small\" [attr.aria-label]=\"messages().clearColor\" (click)=\"onClearClick()\">\n <svg lucideDropletOff [size]=\"16\" aria-hidden=\"true\"></svg>\n </button>\n</div>\n<div class=\"flex flex-col gap-2\">\n @if (showColorInputs()) {\n <div class=\"flex gap-2\">\n <div class=\"flex gap-1\">\n @for (input of colorInputs(); track input.key) {\n <mona-numeric-text-box\n [value]=\"input.value\"\n [minValue]=\"input.min\"\n [maxValue]=\"input.max\"\n [decimals]=\"0\"\n [spinners]=\"false\"\n [nullable]=\"false\"\n [rounded]=\"rounded()\"\n [size]=\"'small'\"\n class=\"w-18\"\n (valueChange)=\"input.change($event)\"\n (inputBlur)=\"onNumericInputBlur()\">\n <ng-template monaNumericTextBoxPrefixTemplate>\n <ng-container\n [ngTemplateOutlet]=\"numericInputPrefixTemplate\"\n [ngTemplateOutletContext]=\"{ $implicit: input.label }\"></ng-container>\n </ng-template>\n </mona-numeric-text-box>\n }\n </div>\n <div class=\"flex flex-1 items-center justify-end\">\n <button\n monaButton\n look=\"ghost\"\n [rounded]=\"rounded()\"\n size=\"small\"\n [attr.aria-label]=\"messages().switchColorMode\"\n (click)=\"onSwitchColorModeClick()\">\n <svg lucideChevronsUpDown [size]=\"16\" aria-hidden=\"true\"></svg>\n </button>\n </div>\n </div>\n }\n @if (showHexInput()) {\n <mona-text-box\n [rounded]=\"rounded()\"\n [value]=\"hex()\"\n (valueChange)=\"onHexChange($event)\"\n (inputBlur)=\"onHexInputBlur()\"\n (inputFocus)=\"onHexInputFocus()\"\n class=\"w-full\">\n <ng-template monaTextBoxPrefixTemplate>\n <ng-container\n [ngTemplateOutlet]=\"numericInputPrefixTemplate\"\n [ngTemplateOutletContext]=\"{ $implicit: 'HEX', classes: 'w-auto px-2' }\"></ng-container>\n </ng-template>\n <ng-template monaTextBoxSuffixTemplate>\n <mona-dropdown-button look=\"ghost\" [attr.aria-label]=\"messages().copyColor\" class=\"h-full\">\n <svg lucideCopy [size]=\"12\"></svg>\n <mona-dropdown-button-item\n [label]=\"messages().copyAsHex\"\n (menuClick)=\"onCopyColorSelect('hex')\"></mona-dropdown-button-item>\n <mona-dropdown-button-item\n [label]=\"messages().copyAsRgb\"\n (menuClick)=\"onCopyColorSelect('rgb')\"></mona-dropdown-button-item>\n </mona-dropdown-button>\n </ng-template>\n </mona-text-box>\n }\n @if (showButtons()) {\n <div class=\"flex items-center justify-end gap-2\">\n <button monaButton [rounded]=\"rounded()\" look=\"primary\" (click)=\"onApply()\">{{ messages().apply }}</button>\n <button monaButton [rounded]=\"rounded()\" (click)=\"onCancel()\">{{ messages().cancel }}</button>\n </div>\n }\n</div>\n\n<ng-template #numericInputPrefixTemplate let-text let-classes=\"classes\">\n <span\n [class]=\"classes\"\n class=\"inline-flex items-center justify-center select-none w-7.5 [background-color:var(--mona-input-addon-background,var(--color-secondary))] h-full text-foreground text-xs font-semibold border-e border-e-input-border\"\n >{{ text }}</span\n >\n</ng-template>\n", dependencies: [{ kind: "component", type: LucideDropletOff, selector: "svg[lucideDropletOff]" }, { kind: "component", type: LucideChevronsUpDown, selector: "svg[lucideChevronsUpDown]" }, { kind: "component", type: NumericTextBoxComponent, selector: "mona-numeric-text-box", inputs: ["formatter", "maxValue", "minValue", "step", "value"], outputs: ["valueChange"] }, { kind: "directive", type: NumericTextBoxPrefixTemplateDirective, selector: "ng-template[monaNumericTextBoxPrefixTemplate]" }, { kind: "directive", type: ButtonDirective, selector: "button[monaButton]", inputs: ["aria-haspopup", "disabled", "iconOnly", "loading", "look", "rounded", "selected", "size", "tabindex", "type", "toggleable", "class"], outputs: ["disabledChange", "loadingChange", "lookChange", "selectedChange"] }, { kind: "component", type: TextBoxComponent, selector: "mona-text-box", inputs: ["clearButton", "disabled", "inputAttributes", "inputClass", "inputStyle", "invalid", "placeholder", "readonly", "required", "rounded", "size", "touched", "type", "class", "value"], outputs: ["inputBlur", "inputFocus", "touch", "valueChange"] }, { kind: "directive", type: TextBoxPrefixTemplateDirective, selector: "ng-template[monaTextBoxPrefixTemplate]" }, { kind: "directive", type: TextBoxSuffixTemplateDirective, selector: "ng-template[monaTextBoxSuffixTemplate]" }, { kind: "component", type: SliderComponent, selector: "mona-slider", inputs: ["aria-label", "aria-labelledby", "value"], outputs: ["valueChange"] }, { kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "component", type: DropdownButtonComponent, selector: "mona-dropdown-button", inputs: ["aria-label", "aria-labelledby", "iconOnly", "disabled", "loading", "look", "rounded", "size", "text", "class"], outputs: ["menuItemClick"] }, { kind: "component", type: DropdownButtonItemComponent, selector: "mona-dropdown-button-item" }, { kind: "component", type: LucideCopy, selector: "svg[lucideCopy]" }] }); }
792
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.0.6", type: ColorGradientComponent, isStandalone: true, selector: "mona-color-gradient", inputs: { disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, format: { classPropertyName: "format", publicName: "format", isSignal: true, isRequired: false, transformFunction: null }, invalid: { classPropertyName: "invalid", publicName: "invalid", isSignal: true, isRequired: false, transformFunction: null }, opacity: { classPropertyName: "opacity", publicName: "opacity", isSignal: true, isRequired: false, transformFunction: null }, required: { classPropertyName: "required", publicName: "required", isSignal: true, isRequired: false, transformFunction: null }, rounded: { classPropertyName: "rounded", publicName: "rounded", isSignal: true, isRequired: false, transformFunction: null }, showButtons: { classPropertyName: "showButtons", publicName: "showButtons", isSignal: true, isRequired: false, transformFunction: null }, showHexInput: { classPropertyName: "showHexInput", publicName: "showHexInput", isSignal: true, isRequired: false, transformFunction: null }, showColorInputs: { classPropertyName: "showColorInputs", publicName: "showColorInputs", isSignal: true, isRequired: false, transformFunction: null }, touched: { classPropertyName: "touched", publicName: "touched", isSignal: true, isRequired: false, transformFunction: null }, value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { apply: "apply", cancel: "cancel", touch: "touch", value: "valueChange" }, host: { properties: { "class": "baseClasses()", "attr.data-disabled": "disabled()", "attr.data-invalid": "invalidState() || null", "attr.aria-invalid": "invalidState() ? 'true' : null" } }, viewQueries: [{ propertyName: "hsvHandle", first: true, predicate: ["hsvPointer"], descendants: true, isSignal: true }, { propertyName: "hsvRectangle", first: true, predicate: ["hsvRectangle"], descendants: true, isSignal: true }], ngImport: i0, template: "<div [class]=\"hsvRectangleClasses()\" [style.background-color]=\"hsvRectangleBackground()\" #hsvRectangle>\n <div\n [class]=\"hsvRectangleHandleClasses()\"\n [style.left.px]=\"hsvHandleLeft()\"\n [style.top.px]=\"hsvHandleTop()\"\n [attr.tabindex]=\"disabled() ? -1 : 0\"\n [attr.role]=\"'slider'\"\n [attr.aria-label]=\"messages().saturationAndValue\"\n [attr.aria-valuemin]=\"0\"\n [attr.aria-valuemax]=\"100\"\n [attr.aria-valuenow]=\"hsv().s\"\n [attr.aria-valuetext]=\"messages().saturationAndValueText(hsv().s ?? 0, hsv().v ?? 0)\"\n [attr.aria-disabled]=\"disabled() || null\"\n (keydown)=\"onHsvHandleKeyDown($event)\"\n (blur)=\"onHsvHandleBlur()\"\n #hsvPointer></div>\n</div>\n<div class=\"flex items-center gap-2\">\n <div class=\"flex flex-1 flex-col gap-1 me-2\">\n <mona-slider\n [minValue]=\"0\"\n [maxValue]=\"360\"\n [trackBackground]=\"'linear-gradient(to right, #ff0000, #ffff00, #00ff00, #00ffff, #0000ff, #ff00ff, #ff0000)'\"\n [selectionBackground]=\"'transparent'\"\n [handleClasses]=\"sliderHandleClasses()\"\n [trackSize]=\"sliderHeight\"\n [rounded]=\"rounded()\"\n [value]=\"hsv().h ?? 0\"\n (valueChange)=\"hueValue$.next($event)\"\n (touch)=\"onSliderBlur()\"></mona-slider>\n @if (opacity()) {\n <mona-slider\n [minValue]=\"0\"\n [maxValue]=\"255\"\n [trackBackground]=\"alphaSliderBackground()\"\n [selectionBackground]=\"'transparent'\"\n [handleClasses]=\"sliderHandleClasses()\"\n [trackSize]=\"sliderHeight\"\n [rounded]=\"rounded()\"\n [value]=\"alpha()\"\n (valueChange)=\"onAlphaChange($event)\"\n (touch)=\"onSliderBlur()\"></mona-slider>\n }\n </div>\n @for (preview of colorPreviews(); track preview.type) {\n <div\n [class]=\"colorPreviewClasses()\"\n [class.cursor-pointer]=\"$index === 1\"\n [style.background-color]=\"preview.color\"\n [attr.title]=\"$index === 1 ? preview.title : null\"\n [attr.aria-label]=\"$index === 1 ? preview.title : null\"\n [attr.aria-hidden]=\"$index === 0 ? 'true' : null\"\n [attr.role]=\"$index === 1 ? 'button' : null\"\n [attr.tabindex]=\"$index === 1 ? 0 : null\"\n (click)=\"preview.onClick?.()\"\n (keydown)=\"onPreviousColorKeyDown($event, preview.onClick)\"></div>\n }\n <button monaButton look=\"ghost\" size=\"small\" [attr.aria-label]=\"messages().clearColor\" (click)=\"onClearClick()\">\n <svg lucideDropletOff [size]=\"16\" aria-hidden=\"true\"></svg>\n </button>\n</div>\n<div class=\"flex flex-col gap-2\">\n @if (showColorInputs()) {\n <div class=\"flex gap-2\">\n <div class=\"flex gap-1\">\n @for (input of colorInputs(); track input.key) {\n <mona-numeric-text-box\n [value]=\"input.value\"\n [minValue]=\"input.min\"\n [maxValue]=\"input.max\"\n [decimals]=\"0\"\n [spinners]=\"false\"\n [nullable]=\"false\"\n [rounded]=\"rounded()\"\n [size]=\"'small'\"\n class=\"w-18\"\n (valueChange)=\"input.change($event)\"\n (inputBlur)=\"onNumericInputBlur()\">\n <ng-template monaNumericTextBoxPrefixTemplate>\n <ng-container\n [ngTemplateOutlet]=\"numericInputPrefixTemplate\"\n [ngTemplateOutletContext]=\"{ $implicit: input.label }\"></ng-container>\n </ng-template>\n </mona-numeric-text-box>\n }\n </div>\n <div class=\"flex flex-1 items-center justify-end\">\n <button\n monaButton\n look=\"ghost\"\n [rounded]=\"rounded()\"\n size=\"small\"\n [attr.aria-label]=\"messages().switchColorMode\"\n (click)=\"onSwitchColorModeClick()\">\n <svg lucideChevronsUpDown [size]=\"16\" aria-hidden=\"true\"></svg>\n </button>\n </div>\n </div>\n }\n @if (showHexInput()) {\n <mona-text-box\n [rounded]=\"rounded()\"\n [value]=\"hex()\"\n (valueChange)=\"onHexChange($event)\"\n (inputBlur)=\"onHexInputBlur()\"\n (inputFocus)=\"onHexInputFocus()\"\n class=\"w-full\">\n <ng-template monaTextBoxPrefixTemplate>\n <ng-container\n [ngTemplateOutlet]=\"numericInputPrefixTemplate\"\n [ngTemplateOutletContext]=\"{ $implicit: 'HEX', classes: 'w-auto px-2' }\"></ng-container>\n </ng-template>\n <ng-template monaTextBoxSuffixTemplate>\n <mona-dropdown-button look=\"ghost\" [attr.aria-label]=\"messages().copyColor\" class=\"h-full\">\n <svg lucideCopy [size]=\"12\"></svg>\n <mona-dropdown-button-item\n [label]=\"messages().copyAsHex\"\n (menuClick)=\"onCopyColorSelect('hex')\"></mona-dropdown-button-item>\n <mona-dropdown-button-item\n [label]=\"messages().copyAsRgb\"\n (menuClick)=\"onCopyColorSelect('rgb')\"></mona-dropdown-button-item>\n </mona-dropdown-button>\n </ng-template>\n </mona-text-box>\n }\n @if (showButtons()) {\n <div class=\"flex items-center justify-end gap-2\">\n <button monaButton [rounded]=\"rounded()\" look=\"primary\" (click)=\"onApply()\">{{ messages().apply }}</button>\n <button monaButton [rounded]=\"rounded()\" (click)=\"onCancel()\">{{ messages().cancel }}</button>\n </div>\n }\n</div>\n\n<ng-template #numericInputPrefixTemplate let-text let-classes=\"classes\">\n <span\n [class]=\"classes\"\n class=\"inline-flex items-center justify-center select-none w-7.5 [background-color:var(--mona-input-addon-background,var(--color-secondary))] h-full text-foreground text-xs font-semibold border-e border-e-input-border\"\n >{{ text }}</span\n >\n</ng-template>\n", dependencies: [{ kind: "component", type: LucideDropletOff, selector: "svg[lucideDropletOff]" }, { kind: "component", type: LucideChevronsUpDown, selector: "svg[lucideChevronsUpDown]" }, { kind: "component", type: NumericTextBoxComponent, selector: "mona-numeric-text-box", inputs: ["formatter", "maxValue", "minValue", "step", "value"], outputs: ["valueChange"] }, { kind: "directive", type: NumericTextBoxPrefixTemplateDirective, selector: "ng-template[monaNumericTextBoxPrefixTemplate]" }, { kind: "directive", type: ButtonDirective, selector: "button[monaButton]", inputs: ["aria-haspopup", "disabled", "iconOnly", "loading", "look", "rounded", "selected", "size", "tabindex", "toggleable", "type", "class"], outputs: ["lookChange", "selectedChange"] }, { kind: "component", type: TextBoxComponent, selector: "mona-text-box", inputs: ["clearButton", "disabled", "inputAttributes", "inputClass", "inputStyle", "invalid", "placeholder", "readonly", "required", "rounded", "size", "touched", "type", "class", "value"], outputs: ["inputBlur", "inputFocus", "touch", "valueChange"] }, { kind: "directive", type: TextBoxPrefixTemplateDirective, selector: "ng-template[monaTextBoxPrefixTemplate]" }, { kind: "directive", type: TextBoxSuffixTemplateDirective, selector: "ng-template[monaTextBoxSuffixTemplate]" }, { kind: "component", type: SliderComponent, selector: "mona-slider", inputs: ["aria-label", "aria-labelledby", "value"], outputs: ["valueChange"] }, { kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "component", type: DropdownButtonComponent, selector: "mona-dropdown-button", inputs: ["aria-label", "aria-labelledby", "iconOnly", "disabled", "loading", "look", "rounded", "size", "text", "class"], outputs: ["menuItemClick"] }, { kind: "component", type: DropdownButtonItemComponent, selector: "mona-dropdown-button-item" }, { kind: "component", type: LucideCopy, selector: "svg[lucideCopy]" }] }); }
793
793
  }
794
794
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.6", ngImport: i0, type: ColorGradientComponent, decorators: [{
795
795
  type: Component,