@joanroucoux/cairn-ui 0.8.1 → 0.9.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 (125) hide show
  1. package/CHANGELOG.md +105 -0
  2. package/README.md +2 -0
  3. package/fesm2022/joanroucoux-cairn-ui-action-bar.mjs +57 -53
  4. package/fesm2022/joanroucoux-cairn-ui-action-bar.mjs.map +1 -1
  5. package/fesm2022/joanroucoux-cairn-ui-alert.mjs +155 -47
  6. package/fesm2022/joanroucoux-cairn-ui-alert.mjs.map +1 -1
  7. package/fesm2022/joanroucoux-cairn-ui-amount.mjs +220 -110
  8. package/fesm2022/joanroucoux-cairn-ui-amount.mjs.map +1 -1
  9. package/fesm2022/joanroucoux-cairn-ui-async.mjs +392 -216
  10. package/fesm2022/joanroucoux-cairn-ui-async.mjs.map +1 -1
  11. package/fesm2022/joanroucoux-cairn-ui-avatar.mjs +145 -68
  12. package/fesm2022/joanroucoux-cairn-ui-avatar.mjs.map +1 -1
  13. package/fesm2022/joanroucoux-cairn-ui-back-link.mjs +87 -47
  14. package/fesm2022/joanroucoux-cairn-ui-back-link.mjs.map +1 -1
  15. package/fesm2022/joanroucoux-cairn-ui-badge.mjs +83 -43
  16. package/fesm2022/joanroucoux-cairn-ui-badge.mjs.map +1 -1
  17. package/fesm2022/joanroucoux-cairn-ui-button.mjs +184 -104
  18. package/fesm2022/joanroucoux-cairn-ui-button.mjs.map +1 -1
  19. package/fesm2022/joanroucoux-cairn-ui-card.mjs +232 -137
  20. package/fesm2022/joanroucoux-cairn-ui-card.mjs.map +1 -1
  21. package/fesm2022/joanroucoux-cairn-ui-choice-chips.mjs +298 -102
  22. package/fesm2022/joanroucoux-cairn-ui-choice-chips.mjs.map +1 -1
  23. package/fesm2022/joanroucoux-cairn-ui-control.mjs +4 -17
  24. package/fesm2022/joanroucoux-cairn-ui-control.mjs.map +1 -1
  25. package/fesm2022/joanroucoux-cairn-ui-delta.mjs +150 -83
  26. package/fesm2022/joanroucoux-cairn-ui-delta.mjs.map +1 -1
  27. package/fesm2022/joanroucoux-cairn-ui-dialog.mjs +508 -471
  28. package/fesm2022/joanroucoux-cairn-ui-dialog.mjs.map +1 -1
  29. package/fesm2022/joanroucoux-cairn-ui-donut.mjs +255 -157
  30. package/fesm2022/joanroucoux-cairn-ui-donut.mjs.map +1 -1
  31. package/fesm2022/joanroucoux-cairn-ui-drawer.mjs +303 -0
  32. package/fesm2022/joanroucoux-cairn-ui-drawer.mjs.map +1 -0
  33. package/fesm2022/joanroucoux-cairn-ui-empty.mjs +76 -35
  34. package/fesm2022/joanroucoux-cairn-ui-empty.mjs.map +1 -1
  35. package/fesm2022/joanroucoux-cairn-ui-external-link.mjs +40 -31
  36. package/fesm2022/joanroucoux-cairn-ui-external-link.mjs.map +1 -1
  37. package/fesm2022/joanroucoux-cairn-ui-fact.mjs +188 -79
  38. package/fesm2022/joanroucoux-cairn-ui-fact.mjs.map +1 -1
  39. package/fesm2022/joanroucoux-cairn-ui-field.mjs +309 -173
  40. package/fesm2022/joanroucoux-cairn-ui-field.mjs.map +1 -1
  41. package/fesm2022/joanroucoux-cairn-ui-filter-chips.mjs +165 -87
  42. package/fesm2022/joanroucoux-cairn-ui-filter-chips.mjs.map +1 -1
  43. package/fesm2022/joanroucoux-cairn-ui-group-header.mjs +269 -0
  44. package/fesm2022/joanroucoux-cairn-ui-group-header.mjs.map +1 -0
  45. package/fesm2022/joanroucoux-cairn-ui-input.mjs +205 -85
  46. package/fesm2022/joanroucoux-cairn-ui-input.mjs.map +1 -1
  47. package/fesm2022/joanroucoux-cairn-ui-line-chart.mjs +838 -512
  48. package/fesm2022/joanroucoux-cairn-ui-line-chart.mjs.map +1 -1
  49. package/fesm2022/joanroucoux-cairn-ui-menu.mjs +401 -225
  50. package/fesm2022/joanroucoux-cairn-ui-menu.mjs.map +1 -1
  51. package/fesm2022/joanroucoux-cairn-ui-meter.mjs +143 -57
  52. package/fesm2022/joanroucoux-cairn-ui-meter.mjs.map +1 -1
  53. package/fesm2022/joanroucoux-cairn-ui-motion.mjs +367 -399
  54. package/fesm2022/joanroucoux-cairn-ui-motion.mjs.map +1 -1
  55. package/fesm2022/joanroucoux-cairn-ui-nav-item.mjs +73 -44
  56. package/fesm2022/joanroucoux-cairn-ui-nav-item.mjs.map +1 -1
  57. package/fesm2022/joanroucoux-cairn-ui-result-group.mjs +191 -0
  58. package/fesm2022/joanroucoux-cairn-ui-result-group.mjs.map +1 -0
  59. package/fesm2022/joanroucoux-cairn-ui-row.mjs +376 -146
  60. package/fesm2022/joanroucoux-cairn-ui-row.mjs.map +1 -1
  61. package/fesm2022/joanroucoux-cairn-ui-segmented.mjs +183 -81
  62. package/fesm2022/joanroucoux-cairn-ui-segmented.mjs.map +1 -1
  63. package/fesm2022/joanroucoux-cairn-ui-select-pill.mjs +233 -0
  64. package/fesm2022/joanroucoux-cairn-ui-select-pill.mjs.map +1 -0
  65. package/fesm2022/joanroucoux-cairn-ui-select.mjs +121 -67
  66. package/fesm2022/joanroucoux-cairn-ui-select.mjs.map +1 -1
  67. package/fesm2022/joanroucoux-cairn-ui-skeleton.mjs +129 -51
  68. package/fesm2022/joanroucoux-cairn-ui-skeleton.mjs.map +1 -1
  69. package/fesm2022/joanroucoux-cairn-ui-stale-link.mjs +80 -39
  70. package/fesm2022/joanroucoux-cairn-ui-stale-link.mjs.map +1 -1
  71. package/fesm2022/joanroucoux-cairn-ui-stat.mjs +85 -55
  72. package/fesm2022/joanroucoux-cairn-ui-stat.mjs.map +1 -1
  73. package/fesm2022/joanroucoux-cairn-ui-switch.mjs +48 -35
  74. package/fesm2022/joanroucoux-cairn-ui-switch.mjs.map +1 -1
  75. package/fesm2022/joanroucoux-cairn-ui-tab-bar.mjs +113 -69
  76. package/fesm2022/joanroucoux-cairn-ui-tab-bar.mjs.map +1 -1
  77. package/fesm2022/joanroucoux-cairn-ui-table.mjs +1036 -310
  78. package/fesm2022/joanroucoux-cairn-ui-table.mjs.map +1 -1
  79. package/fesm2022/joanroucoux-cairn-ui-toast.mjs +240 -127
  80. package/fesm2022/joanroucoux-cairn-ui-toast.mjs.map +1 -1
  81. package/fesm2022/joanroucoux-cairn-ui.mjs +0 -4
  82. package/package.json +17 -1
  83. package/styles/motion.css +1 -13
  84. package/styles/tokens.css +35 -64
  85. package/types/joanroucoux-cairn-ui-action-bar.d.ts +9 -14
  86. package/types/joanroucoux-cairn-ui-alert.d.ts +29 -15
  87. package/types/joanroucoux-cairn-ui-amount.d.ts +64 -32
  88. package/types/joanroucoux-cairn-ui-async.d.ts +85 -38
  89. package/types/joanroucoux-cairn-ui-avatar.d.ts +34 -22
  90. package/types/joanroucoux-cairn-ui-back-link.d.ts +20 -15
  91. package/types/joanroucoux-cairn-ui-badge.d.ts +22 -14
  92. package/types/joanroucoux-cairn-ui-button.d.ts +36 -18
  93. package/types/joanroucoux-cairn-ui-card.d.ts +48 -23
  94. package/types/joanroucoux-cairn-ui-choice-chips.d.ts +91 -35
  95. package/types/joanroucoux-cairn-ui-control.d.ts +9 -18
  96. package/types/joanroucoux-cairn-ui-delta.d.ts +46 -24
  97. package/types/joanroucoux-cairn-ui-dialog.d.ts +124 -57
  98. package/types/joanroucoux-cairn-ui-donut.d.ts +83 -46
  99. package/types/joanroucoux-cairn-ui-drawer.d.ts +73 -0
  100. package/types/joanroucoux-cairn-ui-empty.d.ts +20 -13
  101. package/types/joanroucoux-cairn-ui-external-link.d.ts +6 -10
  102. package/types/joanroucoux-cairn-ui-fact.d.ts +49 -25
  103. package/types/joanroucoux-cairn-ui-field.d.ts +72 -49
  104. package/types/joanroucoux-cairn-ui-filter-chips.d.ts +35 -20
  105. package/types/joanroucoux-cairn-ui-group-header.d.ts +58 -0
  106. package/types/joanroucoux-cairn-ui-input.d.ts +59 -37
  107. package/types/joanroucoux-cairn-ui-line-chart.d.ts +199 -89
  108. package/types/joanroucoux-cairn-ui-menu.d.ts +81 -44
  109. package/types/joanroucoux-cairn-ui-meter.d.ts +44 -22
  110. package/types/joanroucoux-cairn-ui-motion.d.ts +61 -75
  111. package/types/joanroucoux-cairn-ui-nav-item.d.ts +15 -13
  112. package/types/joanroucoux-cairn-ui-result-group.d.ts +52 -0
  113. package/types/joanroucoux-cairn-ui-row.d.ts +79 -37
  114. package/types/joanroucoux-cairn-ui-segmented.d.ts +51 -27
  115. package/types/joanroucoux-cairn-ui-select-pill.d.ts +52 -0
  116. package/types/joanroucoux-cairn-ui-select.d.ts +28 -18
  117. package/types/joanroucoux-cairn-ui-skeleton.d.ts +35 -18
  118. package/types/joanroucoux-cairn-ui-stale-link.d.ts +23 -16
  119. package/types/joanroucoux-cairn-ui-stat.d.ts +26 -21
  120. package/types/joanroucoux-cairn-ui-switch.d.ts +7 -11
  121. package/types/joanroucoux-cairn-ui-tab-bar.d.ts +20 -17
  122. package/types/joanroucoux-cairn-ui-table.d.ts +251 -89
  123. package/types/joanroucoux-cairn-ui-toast.d.ts +46 -36
  124. package/types/joanroucoux-cairn-ui.d.ts +1 -2
  125. package/fesm2022/joanroucoux-cairn-ui.mjs.map +0 -1
@@ -1,183 +1,293 @@
1
- import * as i0 from '@angular/core';
2
- import { input, booleanAttribute, inject, ElementRef, computed, Directive, numberAttribute, signal, contentChildren, Component } from '@angular/core';
3
-
4
- const MENU_CLASSES = 'm-0 min-w-44 p-1 rounded-container bg-(--elevated) shadow-[0_8px_24px_rgb(0_0_0/0.16),inset_0_0_0_1px_var(--border)] text-(--foreground) transition-[opacity,scale,overlay,display] transition-discrete duration-(--duration-fast) not-open:duration-[120ms] ease-out starting:open:opacity-0 starting:open:scale-(--enter-scale) opacity-0 scale-(--enter-scale) open:opacity-100 open:scale-100';
5
- const SHEET_CLASSES = 'max-lg:fixed max-lg:inset-x-4 max-lg:top-auto max-lg:w-auto max-lg:bottom-[calc(76px+env(safe-area-inset-bottom))] max-lg:min-w-0 max-lg:p-1.5 max-lg:bg-(--card) max-lg:shadow-[0_12px_32px_rgb(0_0_0/0.2),inset_0_0_0_1px_var(--border)] max-lg:backdrop:bg-[rgb(0_0_0/0.36)] max-lg:transition-[opacity,translate,overlay,display] max-lg:scale-100 max-lg:translate-y-4 max-lg:open:translate-y-0 max-lg:starting:open:scale-100 max-lg:starting:open:translate-y-4 max-lg:motion-reduce:translate-y-0 max-lg:motion-reduce:starting:open:translate-y-0';
6
- const SHEET_ITEM_CLASSES = 'flex w-full items-center gap-3 lg:pointer-fine:gap-2.5 min-h-12 lg:min-h-11 lg:pointer-fine:min-h-9 px-3 lg:pointer-fine:px-2.5 rounded-[calc(var(--radius-container)-6px)] lg:rounded-[calc(var(--radius-container)-4px)] text-body lg:pointer-fine:text-label text-left whitespace-nowrap hover:bg-(--glow) focus-visible:bg-(--glow) active:bg-(--soft) transition-[background-color] duration-(--duration-fast) ease-out outline-none focus-visible:outline-2 focus-visible:-outline-offset-2 focus-visible:outline-(--ring) [:where(&>svg)]:size-5 [:where(&>svg)]:flex-none lg:[:where(&>svg)]:size-[18px] lg:pointer-fine:[:where(&>svg)]:size-4';
7
- const ITEM_CLASSES = 'flex w-full items-center gap-3 pointer-fine:gap-2.5 min-h-11 pointer-fine:min-h-9 px-3 pointer-fine:px-2.5 rounded-[calc(var(--radius-container)-4px)] text-body pointer-fine:text-label text-left whitespace-nowrap hover:bg-(--glow) focus-visible:bg-(--glow) active:bg-(--soft) transition-[background-color] duration-(--duration-fast) ease-out outline-none focus-visible:outline-2 focus-visible:-outline-offset-2 focus-visible:outline-(--ring) [:where(&>svg)]:size-[18px] [:where(&>svg)]:flex-none pointer-fine:[:where(&>svg)]:size-4';
1
+ import * as i0 from "@angular/core";
2
+ import { Component, Directive, ElementRef, booleanAttribute, computed, contentChildren, inject, input, numberAttribute, signal } from "@angular/core";
3
+ const MENU_CLASSES = "m-0 min-w-44 p-1 rounded-container bg-(--elevated) shadow-[0_8px_24px_rgb(0_0_0/0.16),inset_0_0_0_1px_var(--border)] text-(--foreground) transition-[opacity,scale,overlay,display] transition-discrete duration-(--duration-fast) not-open:duration-[120ms] ease-out starting:open:opacity-0 starting:open:scale-(--enter-scale) opacity-0 scale-(--enter-scale) open:opacity-100 open:scale-100";
4
+ const SHEET_CLASSES = "max-lg:fixed max-lg:inset-x-4 max-lg:top-auto max-lg:w-auto max-lg:bottom-[calc(76px+env(safe-area-inset-bottom))] max-lg:min-w-0 max-lg:p-1.5 max-lg:bg-(--card) max-lg:shadow-[0_12px_32px_rgb(0_0_0/0.2),inset_0_0_0_1px_var(--border)] max-lg:backdrop:bg-[rgb(0_0_0/0.36)] max-lg:transition-[opacity,translate,overlay,display] max-lg:scale-100 max-lg:translate-y-4 max-lg:open:translate-y-0 max-lg:starting:open:scale-100 max-lg:starting:open:translate-y-4 max-lg:motion-reduce:translate-y-0 max-lg:motion-reduce:starting:open:translate-y-0";
5
+ const SHEET_ITEM_CLASSES = "flex w-full items-center gap-3 lg:pointer-fine:gap-2.5 min-h-12 lg:min-h-11 lg:pointer-fine:min-h-9 px-3 lg:pointer-fine:px-2.5 rounded-[calc(var(--radius-container)-6px)] lg:rounded-[calc(var(--radius-container)-4px)] text-body lg:pointer-fine:text-label text-left whitespace-nowrap hover:bg-(--glow) focus-visible:bg-(--glow) active:bg-(--soft) transition-[background-color] duration-(--duration-fast) ease-out outline-none focus-visible:outline-2 focus-visible:-outline-offset-2 focus-visible:outline-(--ring) [:where(&>svg)]:size-5 [:where(&>svg)]:flex-none lg:[:where(&>svg)]:size-[18px] lg:pointer-fine:[:where(&>svg)]:size-4";
6
+ const ITEM_CLASSES = "flex w-full items-center gap-3 pointer-fine:gap-2.5 min-h-11 pointer-fine:min-h-9 px-3 pointer-fine:px-2.5 rounded-[calc(var(--radius-container)-4px)] text-body pointer-fine:text-label text-left whitespace-nowrap hover:bg-(--glow) focus-visible:bg-(--glow) active:bg-(--soft) transition-[background-color] duration-(--duration-fast) ease-out outline-none focus-visible:outline-2 focus-visible:-outline-offset-2 focus-visible:outline-(--ring) [:where(&>svg)]:size-[18px] [:where(&>svg)]:flex-none pointer-fine:[:where(&>svg)]:size-4";
7
+ const CHECK_CLASSES = "after:ms-auto after:block after:h-3 after:w-1.5 after:flex-none after:rotate-45 after:border-r-2 after:border-b-2 after:border-current after:content-['']";
8
8
  const nextId = (() => {
9
- let count = 0;
10
- return () => `ui-menu-${++count}`;
9
+ let count = 0;
10
+ return () => `ui-menu-${++count}`;
11
11
  })();
12
- /**
13
- * One action of a `ui-menu`; `destructive` paints it in `--negative`.
14
- *
15
- * @example
16
- * <button uiMenuItem destructive (click)="remove()">Delete the line</button>
17
- */
18
- class UiMenuItem {
19
- destructive = input(false, { ...(ngDevMode ? { debugName: "destructive" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
20
- #host = inject(ElementRef).nativeElement;
21
- #menu = inject(UiMenu);
22
- classes = computed(() => `${this.#menu.sheet() ? SHEET_ITEM_CLASSES : ITEM_CLASSES}${this.destructive() ? ' text-(--negative)' : ''}`, /* @ts-ignore */
23
- ...(ngDevMode ? [{ debugName: "classes" }] : /* istanbul ignore next */ []));
24
- focus() {
25
- this.#host.focus();
26
- }
27
- hasFocus() {
28
- return this.#host === document.activeElement;
29
- }
30
- onClick() {
31
- this.#menu.close();
32
- }
33
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.7", ngImport: i0, type: UiMenuItem, deps: [], target: i0.ɵɵFactoryTarget.Directive });
34
- static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "22.1.7", type: UiMenuItem, isStandalone: true, selector: "button[uiMenuItem]", inputs: { destructive: { classPropertyName: "destructive", publicName: "destructive", isSignal: true, isRequired: false, transformFunction: null } }, host: { attributes: { "role": "menuitem", "tabindex": "-1" }, listeners: { "click": "onClick()" }, properties: { "class": "classes()" } }, ngImport: i0 });
35
- }
36
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.7", ngImport: i0, type: UiMenuItem, decorators: [{
37
- type: Directive,
38
- args: [{
39
- selector: 'button[uiMenuItem]',
40
- host: {
41
- role: 'menuitem',
42
- tabindex: '-1',
43
- '[class]': 'classes()',
44
- '(click)': 'onClick()',
45
- },
46
- }]
47
- }], propDecorators: { destructive: [{ type: i0.Input, args: [{ isSignal: true, alias: "destructive", required: false }] }] } });
48
- /**
49
- * Secondary actions menu, opened from its trigger through the native Popover API. With `sheet`, below
50
- * 64rem it opens as a bottom action sheet above the tab bar instead of beside its trigger, and
51
- * `heading` names what the actions apply to. `width` fixes the outer popover width in pixels (the sheet
52
- * always spans the screen below 64rem); without it the menu fits its content.
53
- *
54
- * @example
55
- * <button ui-button size="icon" aria-label="More" [uiMenuTrigger]="menu">...</button>
56
- * <ui-menu #menu label="Line actions">
57
- * <button uiMenuItem (click)="edit()">Edit</button>
58
- * <button uiMenuItem destructive (click)="remove()">Delete the line</button>
59
- * </ui-menu>
60
- */
61
- class UiMenu {
62
- label = input.required(/* @ts-ignore */
63
- ...(ngDevMode ? [{ debugName: "label" }] : /* istanbul ignore next */ []));
64
- sheet = input(false, { ...(ngDevMode ? { debugName: "sheet" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
65
- heading = input(/* @ts-ignore */
66
- ...(ngDevMode ? [undefined, { debugName: "heading" }] : /* istanbul ignore next */ []));
67
- width = input(undefined, { ...(ngDevMode ? { debugName: "width" } : /* istanbul ignore next */ {}), transform: numberAttribute });
68
- menuId = nextId();
69
- isOpen = signal(false, /* @ts-ignore */
70
- ...(ngDevMode ? [{ debugName: "isOpen" }] : /* istanbul ignore next */ []));
71
- hasWidth = computed(() => Number.isFinite(this.width()), /* @ts-ignore */
72
- ...(ngDevMode ? [{ debugName: "hasWidth" }] : /* istanbul ignore next */ []));
73
- widthVar = computed(() => (this.hasWidth() ? `${this.width()}px` : null), /* @ts-ignore */
74
- ...(ngDevMode ? [{ debugName: "widthVar" }] : /* istanbul ignore next */ []));
75
- classes = computed(() => {
76
- const width = !this.hasWidth() ? '' : this.sheet() ? ' lg:w-(--ui-menu-width)' : ' w-(--ui-menu-width)';
77
- return `${MENU_CLASSES}${this.sheet() ? ` ${SHEET_CLASSES}` : ''}${width}`;
78
- }, /* @ts-ignore */
79
- ...(ngDevMode ? [{ debugName: "classes" }] : /* istanbul ignore next */ []));
80
- items = contentChildren(UiMenuItem, /* @ts-ignore */
81
- ...(ngDevMode ? [{ debugName: "items" }] : /* istanbul ignore next */ []));
82
- #host = inject(ElementRef).nativeElement;
83
- #trigger = null;
84
- open(trigger) {
85
- this.#trigger = trigger;
86
- this.isOpen.set(true);
87
- if (typeof this.#host.showPopover === 'function') {
88
- this.#host.showPopover();
89
- }
90
- if (this.#isSheet()) {
91
- this.#host.style.position = '';
92
- this.#host.style.top = '';
93
- this.#host.style.left = '';
94
- this.#host.style.right = '';
95
- this.#host.style.bottom = '';
96
- }
97
- else {
98
- this.#position(trigger);
99
- }
100
- this.items()[0]?.focus();
101
- }
102
- close() {
103
- const wasOpen = this.isOpen();
104
- this.#applyClosed();
105
- if (wasOpen && typeof this.#host.hidePopover === 'function') {
106
- this.#host.hidePopover();
107
- }
108
- }
109
- #applyClosed() {
110
- this.isOpen.set(false);
111
- this.#trigger?.focus();
112
- this.#trigger = null;
113
- }
114
- onToggle(event) {
115
- if (event.newState === 'closed') {
116
- this.#applyClosed();
117
- }
118
- }
119
- onKeydown(event) {
120
- if (event.key === 'Tab' || event.key === 'Escape') {
121
- event.preventDefault();
122
- this.close();
123
- return;
124
- }
125
- const items = this.items();
126
- const currentIndex = items.findIndex((item) => item.hasFocus());
127
- const lastIndex = items.length - 1;
128
- let nextIndex;
129
- switch (event.key) {
130
- case 'ArrowDown':
131
- nextIndex = currentIndex >= lastIndex ? 0 : currentIndex + 1;
132
- break;
133
- case 'ArrowUp':
134
- nextIndex = currentIndex <= 0 ? lastIndex : currentIndex - 1;
135
- break;
136
- case 'Home':
137
- nextIndex = 0;
138
- break;
139
- case 'End':
140
- nextIndex = lastIndex;
141
- break;
142
- }
143
- if (nextIndex === undefined) {
144
- return;
145
- }
146
- event.preventDefault();
147
- items[nextIndex]?.focus();
148
- }
149
- #isSheet() {
150
- return this.sheet() && typeof window.matchMedia === 'function' && !window.matchMedia('(min-width: 64rem)').matches;
151
- }
152
- #position(trigger) {
153
- const margin = 8;
154
- const triggerRect = trigger.getBoundingClientRect();
155
- const menuRect = { width: this.#host.offsetWidth, height: this.#host.offsetHeight };
156
- const fitsBelow = window.innerHeight - triggerRect.bottom >= menuRect.height + margin;
157
- const top = fitsBelow ? triggerRect.bottom + 4 : Math.max(margin, triggerRect.top - menuRect.height - 4);
158
- const left = Math.min(Math.max(triggerRect.right - menuRect.width, margin), window.innerWidth - menuRect.width - margin);
159
- this.#host.style.position = 'fixed';
160
- this.#host.style.top = `${Math.min(top, window.innerHeight - menuRect.height - margin)}px`;
161
- this.#host.style.left = `${left}px`;
162
- this.#host.style.right = 'auto';
163
- this.#host.style.bottom = 'auto';
164
- this.#host.style.transformOrigin = fitsBelow ? 'top right' : 'bottom right';
165
- }
166
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.7", ngImport: i0, type: UiMenu, deps: [], target: i0.ɵɵFactoryTarget.Component });
167
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.7", type: UiMenu, isStandalone: true, selector: "ui-menu", inputs: { label: { classPropertyName: "label", publicName: "label", isSignal: true, isRequired: true, transformFunction: null }, sheet: { classPropertyName: "sheet", publicName: "sheet", isSignal: true, isRequired: false, transformFunction: null }, heading: { classPropertyName: "heading", publicName: "heading", isSignal: true, isRequired: false, transformFunction: null }, width: { classPropertyName: "width", publicName: "width", isSignal: true, isRequired: false, transformFunction: null } }, host: { attributes: { "role": "menu", "popover": "auto" }, listeners: { "toggle": "onToggle($event)", "keydown": "onKeydown($event)" }, properties: { "id": "menuId", "style.--ui-menu-width": "widthVar()", "class": "classes()", "attr.aria-label": "label()" } }, queries: [{ propertyName: "items", predicate: UiMenuItem, isSignal: true }], ngImport: i0, template: `
12
+ var UiMenuItem = class UiMenuItem {
13
+ destructive = input(false, {
14
+ ...ngDevMode ? { debugName: "destructive" } : /* istanbul ignore next */ {},
15
+ transform: booleanAttribute
16
+ });
17
+ checked = input(...ngDevMode ? [void 0, { debugName: "checked" }] : /* istanbul ignore next */ []);
18
+ #host = inject(ElementRef).nativeElement;
19
+ #menu = inject(UiMenu);
20
+ role = computed(() => this.checked() === void 0 ? "menuitem" : "menuitemradio", ...ngDevMode ? [{ debugName: "role" }] : /* istanbul ignore next */ []);
21
+ classes = computed(() => `${this.#menu.sheet() ? SHEET_ITEM_CLASSES : ITEM_CLASSES}${this.destructive() ? " text-(--negative)" : ""}${this.checked() ? ` ${CHECK_CLASSES}` : ""}`, ...ngDevMode ? [{ debugName: "classes" }] : /* istanbul ignore next */ []);
22
+ focus() {
23
+ this.#host.focus();
24
+ }
25
+ hasFocus() {
26
+ return this.#host === document.activeElement;
27
+ }
28
+ onClick() {
29
+ this.#menu.close();
30
+ }
31
+ static ɵfac = i0.ɵɵngDeclareFactory({
32
+ minVersion: "12.0.0",
33
+ version: "22.2.0",
34
+ ngImport: i0,
35
+ type: UiMenuItem,
36
+ deps: [],
37
+ target: i0.ɵɵFactoryTarget.Directive
38
+ });
39
+ static ɵdir = i0.ɵɵngDeclareDirective({
40
+ minVersion: "17.1.0",
41
+ version: "22.2.0",
42
+ type: UiMenuItem,
43
+ isStandalone: true,
44
+ selector: "button[uiMenuItem]",
45
+ inputs: {
46
+ destructive: {
47
+ classPropertyName: "destructive",
48
+ publicName: "destructive",
49
+ isSignal: true,
50
+ isRequired: false,
51
+ transformFunction: null
52
+ },
53
+ checked: {
54
+ classPropertyName: "checked",
55
+ publicName: "checked",
56
+ isSignal: true,
57
+ isRequired: false,
58
+ transformFunction: null
59
+ }
60
+ },
61
+ host: {
62
+ attributes: { "tabindex": "-1" },
63
+ listeners: { "click": "onClick()" },
64
+ properties: {
65
+ "attr.role": "role()",
66
+ "attr.aria-checked": "checked() === undefined ? null : checked()",
67
+ "class": "classes()"
68
+ }
69
+ },
70
+ ngImport: i0
71
+ });
72
+ };
73
+ i0.ɵɵngDeclareClassMetadata({
74
+ minVersion: "12.0.0",
75
+ version: "22.2.0",
76
+ ngImport: i0,
77
+ type: UiMenuItem,
78
+ decorators: [{
79
+ type: Directive,
80
+ args: [{
81
+ selector: "button[uiMenuItem]",
82
+ host: {
83
+ "[attr.role]": "role()",
84
+ "[attr.aria-checked]": "checked() === undefined ? null : checked()",
85
+ tabindex: "-1",
86
+ "[class]": "classes()",
87
+ "(click)": "onClick()"
88
+ }
89
+ }]
90
+ }],
91
+ propDecorators: {
92
+ destructive: [{
93
+ type: i0.Input,
94
+ args: [{
95
+ isSignal: true,
96
+ alias: "destructive",
97
+ required: false
98
+ }]
99
+ }],
100
+ checked: [{
101
+ type: i0.Input,
102
+ args: [{
103
+ isSignal: true,
104
+ alias: "checked",
105
+ required: false
106
+ }]
107
+ }]
108
+ }
109
+ });
110
+ var UiMenu = class UiMenu {
111
+ label = input.required(...ngDevMode ? [{ debugName: "label" }] : /* istanbul ignore next */ []);
112
+ sheet = input(false, {
113
+ ...ngDevMode ? { debugName: "sheet" } : /* istanbul ignore next */ {},
114
+ transform: booleanAttribute
115
+ });
116
+ heading = input(...ngDevMode ? [void 0, { debugName: "heading" }] : /* istanbul ignore next */ []);
117
+ width = input(void 0, {
118
+ ...ngDevMode ? { debugName: "width" } : /* istanbul ignore next */ {},
119
+ transform: numberAttribute
120
+ });
121
+ menuId = nextId();
122
+ isOpen = signal(false, ...ngDevMode ? [{ debugName: "isOpen" }] : /* istanbul ignore next */ []);
123
+ hasWidth = computed(() => Number.isFinite(this.width()), ...ngDevMode ? [{ debugName: "hasWidth" }] : /* istanbul ignore next */ []);
124
+ widthVar = computed(() => this.hasWidth() ? `${this.width()}px` : null, ...ngDevMode ? [{ debugName: "widthVar" }] : /* istanbul ignore next */ []);
125
+ classes = computed(() => {
126
+ const width = !this.hasWidth() ? "" : this.sheet() ? " lg:w-(--ui-menu-width)" : " w-(--ui-menu-width)";
127
+ return `${MENU_CLASSES}${this.sheet() ? ` ${SHEET_CLASSES}` : ""}${width}`;
128
+ }, ...ngDevMode ? [{ debugName: "classes" }] : /* istanbul ignore next */ []);
129
+ items = contentChildren(UiMenuItem, ...ngDevMode ? [{ debugName: "items" }] : /* istanbul ignore next */ []);
130
+ #host = inject(ElementRef).nativeElement;
131
+ #trigger = null;
132
+ open(trigger) {
133
+ this.#trigger = trigger;
134
+ this.isOpen.set(true);
135
+ if (typeof this.#host.showPopover === "function") this.#host.showPopover();
136
+ if (this.#isSheet()) {
137
+ this.#host.style.position = "";
138
+ this.#host.style.top = "";
139
+ this.#host.style.left = "";
140
+ this.#host.style.right = "";
141
+ this.#host.style.bottom = "";
142
+ } else this.#position(trigger);
143
+ (this.items().find((item) => item.checked()) ?? this.items()[0])?.focus();
144
+ }
145
+ close() {
146
+ const wasOpen = this.isOpen();
147
+ this.#applyClosed();
148
+ if (wasOpen && typeof this.#host.hidePopover === "function") this.#host.hidePopover();
149
+ }
150
+ #applyClosed() {
151
+ this.isOpen.set(false);
152
+ this.#trigger?.focus();
153
+ this.#trigger = null;
154
+ }
155
+ onToggle(event) {
156
+ if (event.newState === "closed") this.#applyClosed();
157
+ }
158
+ onKeydown(event) {
159
+ if (event.key === "Tab" || event.key === "Escape") {
160
+ event.preventDefault();
161
+ this.close();
162
+ return;
163
+ }
164
+ const items = this.items();
165
+ const currentIndex = items.findIndex((item) => item.hasFocus());
166
+ const lastIndex = items.length - 1;
167
+ let nextIndex;
168
+ switch (event.key) {
169
+ case "ArrowDown":
170
+ nextIndex = currentIndex >= lastIndex ? 0 : currentIndex + 1;
171
+ break;
172
+ case "ArrowUp":
173
+ nextIndex = currentIndex <= 0 ? lastIndex : currentIndex - 1;
174
+ break;
175
+ case "Home":
176
+ nextIndex = 0;
177
+ break;
178
+ case "End": nextIndex = lastIndex;
179
+ }
180
+ if (nextIndex === void 0) return;
181
+ event.preventDefault();
182
+ items[nextIndex]?.focus();
183
+ }
184
+ #isSheet() {
185
+ return this.sheet() && typeof window.matchMedia === "function" && !window.matchMedia("(min-width: 64rem)").matches;
186
+ }
187
+ #position(trigger) {
188
+ const margin = 8;
189
+ const triggerRect = trigger.getBoundingClientRect();
190
+ const menuRect = {
191
+ width: this.#host.offsetWidth,
192
+ height: this.#host.offsetHeight
193
+ };
194
+ const fitsBelow = window.innerHeight - triggerRect.bottom >= menuRect.height + margin;
195
+ const top = fitsBelow ? triggerRect.bottom + 4 : Math.max(margin, triggerRect.top - menuRect.height - 4);
196
+ const left = Math.min(Math.max(triggerRect.right - menuRect.width, margin), window.innerWidth - menuRect.width - margin);
197
+ this.#host.style.position = "fixed";
198
+ this.#host.style.top = `${Math.min(top, window.innerHeight - menuRect.height - margin)}px`;
199
+ this.#host.style.left = `${left}px`;
200
+ this.#host.style.right = "auto";
201
+ this.#host.style.bottom = "auto";
202
+ this.#host.style.transformOrigin = fitsBelow ? "top right" : "bottom right";
203
+ }
204
+ static ɵfac = i0.ɵɵngDeclareFactory({
205
+ minVersion: "12.0.0",
206
+ version: "22.2.0",
207
+ ngImport: i0,
208
+ type: UiMenu,
209
+ deps: [],
210
+ target: i0.ɵɵFactoryTarget.Component
211
+ });
212
+ static ɵcmp = i0.ɵɵngDeclareComponent({
213
+ minVersion: "17.0.0",
214
+ version: "22.2.0",
215
+ type: UiMenu,
216
+ isStandalone: true,
217
+ selector: "ui-menu",
218
+ inputs: {
219
+ label: {
220
+ classPropertyName: "label",
221
+ publicName: "label",
222
+ isSignal: true,
223
+ isRequired: true,
224
+ transformFunction: null
225
+ },
226
+ sheet: {
227
+ classPropertyName: "sheet",
228
+ publicName: "sheet",
229
+ isSignal: true,
230
+ isRequired: false,
231
+ transformFunction: null
232
+ },
233
+ heading: {
234
+ classPropertyName: "heading",
235
+ publicName: "heading",
236
+ isSignal: true,
237
+ isRequired: false,
238
+ transformFunction: null
239
+ },
240
+ width: {
241
+ classPropertyName: "width",
242
+ publicName: "width",
243
+ isSignal: true,
244
+ isRequired: false,
245
+ transformFunction: null
246
+ }
247
+ },
248
+ host: {
249
+ attributes: {
250
+ "role": "menu",
251
+ "popover": "auto"
252
+ },
253
+ listeners: {
254
+ "toggle": "onToggle($event)",
255
+ "keydown": "onKeydown($event)"
256
+ },
257
+ properties: {
258
+ "id": "menuId",
259
+ "style.--ui-menu-width": "widthVar()",
260
+ "class": "classes()",
261
+ "attr.aria-label": "label()"
262
+ }
263
+ },
264
+ queries: [{
265
+ propertyName: "items",
266
+ predicate: UiMenuItem,
267
+ isSignal: true
268
+ }],
269
+ ngImport: i0,
270
+ template: `
168
271
  @if (sheet() && heading()) {
169
272
  <div aria-hidden="true" class="text-label px-3 pt-2 pb-1.5 leading-[17px] text-(--muted-foreground) lg:hidden">
170
273
  {{ heading() }}
171
274
  </div>
172
275
  }
173
276
  <ng-content />
174
- `, isInline: true });
175
- }
176
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.7", ngImport: i0, type: UiMenu, decorators: [{
177
- type: Component,
178
- args: [{
179
- selector: 'ui-menu',
180
- template: `
277
+ `,
278
+ isInline: true
279
+ });
280
+ };
281
+ i0.ɵɵngDeclareClassMetadata({
282
+ minVersion: "12.0.0",
283
+ version: "22.2.0",
284
+ ngImport: i0,
285
+ type: UiMenu,
286
+ decorators: [{
287
+ type: Component,
288
+ args: [{
289
+ selector: "ui-menu",
290
+ template: `
181
291
  @if (sheet() && heading()) {
182
292
  <div aria-hidden="true" class="text-label px-3 pt-2 pb-1.5 leading-[17px] text-(--muted-foreground) lg:hidden">
183
293
  {{ heading() }}
@@ -185,57 +295,123 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.7", ngImpor
185
295
  }
186
296
  <ng-content />
187
297
  `,
188
- host: {
189
- role: 'menu',
190
- popover: 'auto',
191
- '[id]': 'menuId',
192
- '[style.--ui-menu-width]': 'widthVar()',
193
- '[class]': 'classes()',
194
- '[attr.aria-label]': 'label()',
195
- '(toggle)': 'onToggle($event)',
196
- '(keydown)': 'onKeydown($event)',
197
- },
198
- }]
199
- }], propDecorators: { label: [{ type: i0.Input, args: [{ isSignal: true, alias: "label", required: true }] }], sheet: [{ type: i0.Input, args: [{ isSignal: true, alias: "sheet", required: false }] }], heading: [{ type: i0.Input, args: [{ isSignal: true, alias: "heading", required: false }] }], width: [{ type: i0.Input, args: [{ isSignal: true, alias: "width", required: false }] }], items: [{ type: i0.ContentChildren, args: [i0.forwardRef(() => UiMenuItem), { isSignal: true }] }] } });
200
- /**
201
- * Opens a `ui-menu` from a trigger element and wires `aria-haspopup`, `aria-expanded` and
202
- * `aria-controls` on it.
203
- *
204
- * @example
205
- * <button ui-button size="icon" aria-label="More" [uiMenuTrigger]="menu">...</button>
206
- */
207
- class UiMenuTrigger {
208
- uiMenuTrigger = input.required(/* @ts-ignore */
209
- ...(ngDevMode ? [{ debugName: "uiMenuTrigger" }] : /* istanbul ignore next */ []));
210
- #host = inject(ElementRef).nativeElement;
211
- toggle() {
212
- const menu = this.uiMenuTrigger();
213
- if (menu.isOpen()) {
214
- menu.close();
215
- }
216
- else {
217
- menu.open(this.#host);
218
- }
219
- }
220
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.7", ngImport: i0, type: UiMenuTrigger, deps: [], target: i0.ɵɵFactoryTarget.Directive });
221
- static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "22.1.7", type: UiMenuTrigger, isStandalone: true, selector: "[uiMenuTrigger]", inputs: { uiMenuTrigger: { classPropertyName: "uiMenuTrigger", publicName: "uiMenuTrigger", isSignal: true, isRequired: true, transformFunction: null } }, host: { attributes: { "aria-haspopup": "menu" }, listeners: { "click": "toggle()" }, properties: { "attr.aria-expanded": "uiMenuTrigger().isOpen()", "attr.aria-controls": "uiMenuTrigger().menuId" } }, ngImport: i0 });
222
- }
223
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.7", ngImport: i0, type: UiMenuTrigger, decorators: [{
224
- type: Directive,
225
- args: [{
226
- selector: '[uiMenuTrigger]',
227
- host: {
228
- 'aria-haspopup': 'menu',
229
- '[attr.aria-expanded]': 'uiMenuTrigger().isOpen()',
230
- '[attr.aria-controls]': 'uiMenuTrigger().menuId',
231
- '(click)': 'toggle()',
232
- },
233
- }]
234
- }], propDecorators: { uiMenuTrigger: [{ type: i0.Input, args: [{ isSignal: true, alias: "uiMenuTrigger", required: true }] }] } });
235
-
236
- /**
237
- * Generated bundle index. Do not edit.
238
- */
239
-
298
+ host: {
299
+ role: "menu",
300
+ popover: "auto",
301
+ "[id]": "menuId",
302
+ "[style.--ui-menu-width]": "widthVar()",
303
+ "[class]": "classes()",
304
+ "[attr.aria-label]": "label()",
305
+ "(toggle)": "onToggle($event)",
306
+ "(keydown)": "onKeydown($event)"
307
+ }
308
+ }]
309
+ }],
310
+ propDecorators: {
311
+ label: [{
312
+ type: i0.Input,
313
+ args: [{
314
+ isSignal: true,
315
+ alias: "label",
316
+ required: true
317
+ }]
318
+ }],
319
+ sheet: [{
320
+ type: i0.Input,
321
+ args: [{
322
+ isSignal: true,
323
+ alias: "sheet",
324
+ required: false
325
+ }]
326
+ }],
327
+ heading: [{
328
+ type: i0.Input,
329
+ args: [{
330
+ isSignal: true,
331
+ alias: "heading",
332
+ required: false
333
+ }]
334
+ }],
335
+ width: [{
336
+ type: i0.Input,
337
+ args: [{
338
+ isSignal: true,
339
+ alias: "width",
340
+ required: false
341
+ }]
342
+ }],
343
+ items: [{
344
+ type: i0.ContentChildren,
345
+ args: [i0.forwardRef(() => UiMenuItem), { isSignal: true }]
346
+ }]
347
+ }
348
+ });
349
+ var UiMenuTrigger = class UiMenuTrigger {
350
+ uiMenuTrigger = input.required(...ngDevMode ? [{ debugName: "uiMenuTrigger" }] : /* istanbul ignore next */ []);
351
+ #host = inject(ElementRef).nativeElement;
352
+ toggle() {
353
+ const menu = this.uiMenuTrigger();
354
+ if (menu.isOpen()) menu.close();
355
+ else menu.open(this.#host);
356
+ }
357
+ static ɵfac = i0.ɵɵngDeclareFactory({
358
+ minVersion: "12.0.0",
359
+ version: "22.2.0",
360
+ ngImport: i0,
361
+ type: UiMenuTrigger,
362
+ deps: [],
363
+ target: i0.ɵɵFactoryTarget.Directive
364
+ });
365
+ static ɵdir = i0.ɵɵngDeclareDirective({
366
+ minVersion: "17.1.0",
367
+ version: "22.2.0",
368
+ type: UiMenuTrigger,
369
+ isStandalone: true,
370
+ selector: "[uiMenuTrigger]",
371
+ inputs: { uiMenuTrigger: {
372
+ classPropertyName: "uiMenuTrigger",
373
+ publicName: "uiMenuTrigger",
374
+ isSignal: true,
375
+ isRequired: true,
376
+ transformFunction: null
377
+ } },
378
+ host: {
379
+ attributes: { "aria-haspopup": "menu" },
380
+ listeners: { "click": "toggle()" },
381
+ properties: {
382
+ "attr.aria-expanded": "uiMenuTrigger().isOpen()",
383
+ "attr.aria-controls": "uiMenuTrigger().menuId"
384
+ }
385
+ },
386
+ ngImport: i0
387
+ });
388
+ };
389
+ i0.ɵɵngDeclareClassMetadata({
390
+ minVersion: "12.0.0",
391
+ version: "22.2.0",
392
+ ngImport: i0,
393
+ type: UiMenuTrigger,
394
+ decorators: [{
395
+ type: Directive,
396
+ args: [{
397
+ selector: "[uiMenuTrigger]",
398
+ host: {
399
+ "aria-haspopup": "menu",
400
+ "[attr.aria-expanded]": "uiMenuTrigger().isOpen()",
401
+ "[attr.aria-controls]": "uiMenuTrigger().menuId",
402
+ "(click)": "toggle()"
403
+ }
404
+ }]
405
+ }],
406
+ propDecorators: { uiMenuTrigger: [{
407
+ type: i0.Input,
408
+ args: [{
409
+ isSignal: true,
410
+ alias: "uiMenuTrigger",
411
+ required: true
412
+ }]
413
+ }] }
414
+ });
240
415
  export { UiMenu, UiMenuItem, UiMenuTrigger };
241
- //# sourceMappingURL=joanroucoux-cairn-ui-menu.mjs.map
416
+
417
+ //# sourceMappingURL=joanroucoux-cairn-ui-menu.mjs.map