@hyalo/angular 0.1.0 → 0.3.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (198) hide show
  1. package/CHANGELOG.md +95 -41
  2. package/README.md +46 -32
  3. package/fesm2022/hyalo-angular-accordion.mjs +6 -6
  4. package/fesm2022/hyalo-angular-accordion.mjs.map +1 -1
  5. package/fesm2022/hyalo-angular-alert.mjs +171 -0
  6. package/fesm2022/hyalo-angular-alert.mjs.map +1 -0
  7. package/fesm2022/hyalo-angular-aspect-ratio.mjs +64 -0
  8. package/fesm2022/hyalo-angular-aspect-ratio.mjs.map +1 -0
  9. package/fesm2022/hyalo-angular-avatar.mjs +169 -0
  10. package/fesm2022/hyalo-angular-avatar.mjs.map +1 -0
  11. package/fesm2022/hyalo-angular-badge.mjs +268 -0
  12. package/fesm2022/hyalo-angular-badge.mjs.map +1 -0
  13. package/fesm2022/hyalo-angular-bento.mjs +132 -0
  14. package/fesm2022/hyalo-angular-bento.mjs.map +1 -0
  15. package/fesm2022/hyalo-angular-blocks.mjs +985 -0
  16. package/fesm2022/hyalo-angular-blocks.mjs.map +1 -0
  17. package/fesm2022/hyalo-angular-border-beam.mjs +73 -0
  18. package/fesm2022/hyalo-angular-border-beam.mjs.map +1 -0
  19. package/fesm2022/hyalo-angular-breadcrumb.mjs +77 -0
  20. package/fesm2022/hyalo-angular-breadcrumb.mjs.map +1 -0
  21. package/fesm2022/hyalo-angular-button-group.mjs +90 -0
  22. package/fesm2022/hyalo-angular-button-group.mjs.map +1 -0
  23. package/fesm2022/hyalo-angular-button.mjs +4 -3
  24. package/fesm2022/hyalo-angular-button.mjs.map +1 -1
  25. package/fesm2022/hyalo-angular-card.mjs +2 -2
  26. package/fesm2022/hyalo-angular-card.mjs.map +1 -1
  27. package/fesm2022/hyalo-angular-carousel.mjs +709 -0
  28. package/fesm2022/hyalo-angular-carousel.mjs.map +1 -0
  29. package/fesm2022/hyalo-angular-chapter-nav.mjs +336 -0
  30. package/fesm2022/hyalo-angular-chapter-nav.mjs.map +1 -0
  31. package/fesm2022/hyalo-angular-chart-engine-DSJop6He.mjs +5 -0
  32. package/fesm2022/hyalo-angular-chart-engine-DSJop6He.mjs.map +1 -0
  33. package/fesm2022/hyalo-angular-chart.mjs +391 -0
  34. package/fesm2022/hyalo-angular-chart.mjs.map +1 -0
  35. package/fesm2022/hyalo-angular-choice.mjs +2 -1
  36. package/fesm2022/hyalo-angular-choice.mjs.map +1 -1
  37. package/fesm2022/hyalo-angular-code-block-highlight-B20d5C76.mjs +40 -0
  38. package/fesm2022/hyalo-angular-code-block-highlight-B20d5C76.mjs.map +1 -0
  39. package/fesm2022/hyalo-angular-code-block.mjs +161 -0
  40. package/fesm2022/hyalo-angular-code-block.mjs.map +1 -0
  41. package/fesm2022/hyalo-angular-command.mjs +193 -0
  42. package/fesm2022/hyalo-angular-command.mjs.map +1 -0
  43. package/fesm2022/hyalo-angular-copy.mjs +138 -0
  44. package/fesm2022/hyalo-angular-copy.mjs.map +1 -0
  45. package/fesm2022/hyalo-angular-core.mjs +424 -0
  46. package/fesm2022/hyalo-angular-core.mjs.map +1 -0
  47. package/fesm2022/hyalo-angular-description-list.mjs +57 -0
  48. package/fesm2022/hyalo-angular-description-list.mjs.map +1 -0
  49. package/fesm2022/hyalo-angular-dialog.mjs +51 -22
  50. package/fesm2022/hyalo-angular-dialog.mjs.map +1 -1
  51. package/fesm2022/hyalo-angular-divider.mjs +66 -0
  52. package/fesm2022/hyalo-angular-divider.mjs.map +1 -0
  53. package/fesm2022/hyalo-angular-empty-state.mjs +123 -0
  54. package/fesm2022/hyalo-angular-empty-state.mjs.map +1 -0
  55. package/fesm2022/hyalo-angular-field.mjs +41 -9
  56. package/fesm2022/hyalo-angular-field.mjs.map +1 -1
  57. package/fesm2022/hyalo-angular-filter.mjs +309 -0
  58. package/fesm2022/hyalo-angular-filter.mjs.map +1 -0
  59. package/fesm2022/hyalo-angular-hotspot.mjs +225 -0
  60. package/fesm2022/hyalo-angular-hotspot.mjs.map +1 -0
  61. package/fesm2022/hyalo-angular-hover-card.mjs +233 -0
  62. package/fesm2022/hyalo-angular-hover-card.mjs.map +1 -0
  63. package/fesm2022/hyalo-angular-icon.mjs +42 -0
  64. package/fesm2022/hyalo-angular-icon.mjs.map +1 -1
  65. package/fesm2022/hyalo-angular-image-compare.mjs +168 -0
  66. package/fesm2022/hyalo-angular-image-compare.mjs.map +1 -0
  67. package/fesm2022/hyalo-angular-interaction.mjs +32 -41
  68. package/fesm2022/hyalo-angular-interaction.mjs.map +1 -1
  69. package/fesm2022/hyalo-angular-kbd.mjs +41 -0
  70. package/fesm2022/hyalo-angular-kbd.mjs.map +1 -0
  71. package/fesm2022/hyalo-angular-lightbox.mjs +228 -0
  72. package/fesm2022/hyalo-angular-lightbox.mjs.map +1 -0
  73. package/fesm2022/hyalo-angular-link.mjs +42 -0
  74. package/fesm2022/hyalo-angular-link.mjs.map +1 -0
  75. package/fesm2022/hyalo-angular-list.mjs +131 -0
  76. package/fesm2022/hyalo-angular-list.mjs.map +1 -0
  77. package/fesm2022/hyalo-angular-marquee.mjs +197 -0
  78. package/fesm2022/hyalo-angular-marquee.mjs.map +1 -0
  79. package/fesm2022/hyalo-angular-menu.mjs +423 -0
  80. package/fesm2022/hyalo-angular-menu.mjs.map +1 -0
  81. package/fesm2022/hyalo-angular-mesh.mjs +126 -0
  82. package/fesm2022/hyalo-angular-mesh.mjs.map +1 -0
  83. package/fesm2022/hyalo-angular-motion.mjs +620 -0
  84. package/fesm2022/hyalo-angular-motion.mjs.map +1 -0
  85. package/fesm2022/hyalo-angular-navbar.mjs +1 -1
  86. package/fesm2022/hyalo-angular-navbar.mjs.map +1 -1
  87. package/fesm2022/hyalo-angular-navigation-menu.mjs +222 -0
  88. package/fesm2022/hyalo-angular-navigation-menu.mjs.map +1 -0
  89. package/fesm2022/hyalo-angular-number-ticker.mjs +174 -0
  90. package/fesm2022/hyalo-angular-number-ticker.mjs.map +1 -0
  91. package/fesm2022/hyalo-angular-overlay.mjs +71 -2
  92. package/fesm2022/hyalo-angular-overlay.mjs.map +1 -1
  93. package/fesm2022/hyalo-angular-pagination.mjs +187 -0
  94. package/fesm2022/hyalo-angular-pagination.mjs.map +1 -0
  95. package/fesm2022/hyalo-angular-popover.mjs +34 -5
  96. package/fesm2022/hyalo-angular-popover.mjs.map +1 -1
  97. package/fesm2022/hyalo-angular-progress.mjs +209 -0
  98. package/fesm2022/hyalo-angular-progress.mjs.map +1 -0
  99. package/fesm2022/hyalo-angular-progressive-blur.mjs +73 -0
  100. package/fesm2022/hyalo-angular-progressive-blur.mjs.map +1 -0
  101. package/fesm2022/hyalo-angular-refraction-renderer-5ZA-kfsA.mjs +186 -0
  102. package/fesm2022/hyalo-angular-refraction-renderer-5ZA-kfsA.mjs.map +1 -0
  103. package/fesm2022/hyalo-angular-refraction.mjs +178 -0
  104. package/fesm2022/hyalo-angular-refraction.mjs.map +1 -0
  105. package/fesm2022/hyalo-angular-scroll-area.mjs +93 -0
  106. package/fesm2022/hyalo-angular-scroll-area.mjs.map +1 -0
  107. package/fesm2022/hyalo-angular-scroll-to-top.mjs +127 -0
  108. package/fesm2022/hyalo-angular-scroll-to-top.mjs.map +1 -0
  109. package/fesm2022/hyalo-angular-segmented.mjs +1 -1
  110. package/fesm2022/hyalo-angular-segmented.mjs.map +1 -1
  111. package/fesm2022/hyalo-angular-select.mjs +112 -15
  112. package/fesm2022/hyalo-angular-select.mjs.map +1 -1
  113. package/fesm2022/hyalo-angular-sidebar.mjs +241 -0
  114. package/fesm2022/hyalo-angular-sidebar.mjs.map +1 -0
  115. package/fesm2022/hyalo-angular-skeleton.mjs +131 -0
  116. package/fesm2022/hyalo-angular-skeleton.mjs.map +1 -0
  117. package/fesm2022/hyalo-angular-sparkline.mjs +110 -0
  118. package/fesm2022/hyalo-angular-sparkline.mjs.map +1 -0
  119. package/fesm2022/hyalo-angular-split-text.mjs +126 -0
  120. package/fesm2022/hyalo-angular-split-text.mjs.map +1 -0
  121. package/fesm2022/hyalo-angular-stat.mjs +193 -0
  122. package/fesm2022/hyalo-angular-stat.mjs.map +1 -0
  123. package/fesm2022/hyalo-angular-stepper.mjs +254 -0
  124. package/fesm2022/hyalo-angular-stepper.mjs.map +1 -0
  125. package/fesm2022/hyalo-angular-table.mjs +335 -0
  126. package/fesm2022/hyalo-angular-table.mjs.map +1 -0
  127. package/fesm2022/hyalo-angular-tabs.mjs +1 -1
  128. package/fesm2022/hyalo-angular-tabs.mjs.map +1 -1
  129. package/fesm2022/hyalo-angular-theme.mjs +1 -1
  130. package/fesm2022/hyalo-angular-theme.mjs.map +1 -1
  131. package/fesm2022/hyalo-angular-timeline.mjs +157 -0
  132. package/fesm2022/hyalo-angular-timeline.mjs.map +1 -0
  133. package/fesm2022/hyalo-angular-toast.mjs +2 -1
  134. package/fesm2022/hyalo-angular-toast.mjs.map +1 -1
  135. package/fesm2022/hyalo-angular.mjs +2 -473
  136. package/package.json +198 -2
  137. package/styles/parts/field.css +44 -36
  138. package/styles/parts/glass.css +2 -0
  139. package/styles/parts/motion.css +19 -0
  140. package/styles/parts/typography.css +17 -0
  141. package/types/hyalo-angular-accordion.d.ts +1 -1
  142. package/types/hyalo-angular-alert.d.ts +47 -0
  143. package/types/hyalo-angular-aspect-ratio.d.ts +13 -0
  144. package/types/hyalo-angular-avatar.d.ts +39 -0
  145. package/types/hyalo-angular-badge.d.ts +82 -0
  146. package/types/hyalo-angular-bento.d.ts +25 -0
  147. package/types/hyalo-angular-blocks.d.ts +272 -0
  148. package/types/hyalo-angular-border-beam.d.ts +15 -0
  149. package/types/hyalo-angular-breadcrumb.d.ts +22 -0
  150. package/types/hyalo-angular-button-group.d.ts +19 -0
  151. package/types/hyalo-angular-button.d.ts +4 -3
  152. package/types/hyalo-angular-card.d.ts +1 -1
  153. package/types/hyalo-angular-carousel.d.ts +147 -0
  154. package/types/hyalo-angular-chapter-nav.d.ts +79 -0
  155. package/types/hyalo-angular-chart.d.ts +90 -0
  156. package/types/hyalo-angular-code-block.d.ts +46 -0
  157. package/types/hyalo-angular-command.d.ts +41 -0
  158. package/types/hyalo-angular-copy.d.ts +39 -0
  159. package/types/hyalo-angular-core.d.ts +210 -0
  160. package/types/hyalo-angular-description-list.d.ts +16 -0
  161. package/types/hyalo-angular-dialog.d.ts +2 -1
  162. package/types/hyalo-angular-divider.d.ts +12 -0
  163. package/types/hyalo-angular-empty-state.d.ts +30 -0
  164. package/types/hyalo-angular-field.d.ts +10 -4
  165. package/types/hyalo-angular-filter.d.ts +122 -0
  166. package/types/hyalo-angular-hotspot.d.ts +70 -0
  167. package/types/hyalo-angular-hover-card.d.ts +47 -0
  168. package/types/hyalo-angular-image-compare.d.ts +55 -0
  169. package/types/hyalo-angular-kbd.d.ts +5 -0
  170. package/types/hyalo-angular-lightbox.d.ts +67 -0
  171. package/types/hyalo-angular-link.d.ts +5 -0
  172. package/types/hyalo-angular-list.d.ts +30 -0
  173. package/types/hyalo-angular-marquee.d.ts +48 -0
  174. package/types/hyalo-angular-menu.d.ts +105 -0
  175. package/types/hyalo-angular-mesh.d.ts +36 -0
  176. package/types/hyalo-angular-motion.d.ts +218 -0
  177. package/types/hyalo-angular-navigation-menu.d.ts +47 -0
  178. package/types/hyalo-angular-number-ticker.d.ts +52 -0
  179. package/types/hyalo-angular-overlay.d.ts +9 -0
  180. package/types/hyalo-angular-pagination.d.ts +59 -0
  181. package/types/hyalo-angular-popover.d.ts +10 -0
  182. package/types/hyalo-angular-progress.d.ts +46 -0
  183. package/types/hyalo-angular-progressive-blur.d.ts +14 -0
  184. package/types/hyalo-angular-refraction.d.ts +46 -0
  185. package/types/hyalo-angular-scroll-area.d.ts +18 -0
  186. package/types/hyalo-angular-scroll-to-top.d.ts +31 -0
  187. package/types/hyalo-angular-segmented.d.ts +1 -1
  188. package/types/hyalo-angular-select.d.ts +49 -3
  189. package/types/hyalo-angular-sidebar.d.ts +57 -0
  190. package/types/hyalo-angular-skeleton.d.ts +34 -0
  191. package/types/hyalo-angular-sparkline.d.ts +19 -0
  192. package/types/hyalo-angular-split-text.d.ts +24 -0
  193. package/types/hyalo-angular-stat.d.ts +56 -0
  194. package/types/hyalo-angular-stepper.d.ts +63 -0
  195. package/types/hyalo-angular-table.d.ts +125 -0
  196. package/types/hyalo-angular-timeline.d.ts +36 -0
  197. package/types/hyalo-angular.d.ts +2 -345
  198. package/fesm2022/hyalo-angular.mjs.map +0 -1
@@ -0,0 +1,233 @@
1
+ import { DOCUMENT } from "@angular/common";
2
+ import { createFlexibleConnectedPositionStrategy, createOverlayRef, createRepositionScrollStrategy } from "@angular/cdk/overlay";
3
+ import { TemplatePortal } from "@angular/cdk/portal";
4
+ import * as i0 from "@angular/core";
5
+ import { DestroyRef, Directive, ElementRef, Injector, ViewContainerRef, inject, input, signal } from "@angular/core";
6
+ import { HyFidelity, injectId } from "@hyalo/angular/core";
7
+ import { HyHoverIntent, hyConnectedPositions } from "@hyalo/angular/overlay";
8
+ import { take } from "rxjs";
9
+ var HyHoverCard = class HyHoverCard {
10
+ content = input.required({
11
+ ...ngDevMode ? { debugName: "content" } : /* istanbul ignore next */ {},
12
+ alias: "hyHoverCard"
13
+ });
14
+ hoverCardLabel = input.required(...ngDevMode ? [{ debugName: "hoverCardLabel" }] : /* istanbul ignore next */ []);
15
+ placement = input("top", ...ngDevMode ? [{ debugName: "placement" }] : /* istanbul ignore next */ []);
16
+ open = signal(false, ...ngDevMode ? [{ debugName: "open" }] : /* istanbul ignore next */ []);
17
+ id = injectId("hover-card");
18
+ injector = inject(Injector);
19
+ host = inject(ElementRef);
20
+ container = inject(ViewContainerRef);
21
+ fidelity = inject(HyFidelity);
22
+ document = inject(DOCUMENT);
23
+ intent = new HyHoverIntent(this.document);
24
+ ref;
25
+ timer;
26
+ disposed = false;
27
+ suppressFocus = false;
28
+ focusTrigger() {
29
+ if (!this.suppressFocus) this.show();
30
+ }
31
+ constructor() {
32
+ inject(DestroyRef).onDestroy(() => {
33
+ this.disposed = true;
34
+ clearTimeout(this.timer);
35
+ this.intent.cancel();
36
+ this.ref?.dispose();
37
+ });
38
+ }
39
+ enter(event) {
40
+ this.intent.cancel();
41
+ if (event.pointerType === "touch") return;
42
+ clearTimeout(this.timer);
43
+ this.timer = setTimeout(() => this.show(), 250);
44
+ }
45
+ leave(event) {
46
+ clearTimeout(this.timer);
47
+ this.intent.leave(event, this.ref?.overlayElement, () => {
48
+ if (this.ref?.overlayElement.contains(this.document.activeElement) || this.host.nativeElement.contains(this.document.activeElement)) return;
49
+ this.hide();
50
+ });
51
+ }
52
+ focusOut(event) {
53
+ if (event.relatedTarget && this.ref?.overlayElement.contains(event.relatedTarget)) return;
54
+ this.leave();
55
+ }
56
+ escape(event) {
57
+ if (this.open()) {
58
+ event.preventDefault();
59
+ event.stopPropagation();
60
+ this.hide();
61
+ this.suppressFocus = true;
62
+ this.host.nativeElement.focus();
63
+ this.suppressFocus = false;
64
+ }
65
+ }
66
+ focusCard(event) {
67
+ event.preventDefault();
68
+ this.show();
69
+ const pane = this.ref?.overlayElement;
70
+ if (!pane) return;
71
+ const focusable = pane.querySelector("a[href],button:not([disabled]),input:not([disabled]),[tabindex=\"0\"]");
72
+ pane.tabIndex = -1;
73
+ (focusable ?? pane).focus();
74
+ }
75
+ show() {
76
+ clearTimeout(this.timer);
77
+ if (this.disposed || this.open()) return;
78
+ if (!this.ref) {
79
+ const position = createFlexibleConnectedPositionStrategy(this.injector, this.host).withPositions(hyConnectedPositions(this.placement(), 8)).withViewportMargin(12).withPush(true);
80
+ this.ref = createOverlayRef(this.injector, {
81
+ positionStrategy: position,
82
+ scrollStrategy: createRepositionScrollStrategy(this.injector),
83
+ panelClass: "hy-hover-card-pane"
84
+ });
85
+ const pane = this.ref.overlayElement;
86
+ pane.classList.add("hy-glass");
87
+ pane.style.cssText = "max-inline-size:min(22rem,calc(100vw - 2rem));max-block-size:70dvh;overflow:auto;padding:1.25rem;border-radius:var(--hy-radius-m);border:1px solid var(--hy-line-strong);color:var(--hy-ink)";
88
+ pane.id = this.id;
89
+ pane.setAttribute("role", "dialog");
90
+ pane.addEventListener("pointerenter", () => {
91
+ clearTimeout(this.timer);
92
+ this.intent.cancel();
93
+ });
94
+ pane.addEventListener("pointerleave", () => this.leave());
95
+ pane.addEventListener("focusout", (event) => {
96
+ const next = event.relatedTarget;
97
+ if (!next || !pane.contains(next) && !this.host.nativeElement.contains(next)) this.leave();
98
+ });
99
+ this.ref.keydownEvents().subscribe((event) => {
100
+ if (event.key === "Escape") this.escape(event);
101
+ });
102
+ this.ref.outsidePointerEvents().subscribe((event) => {
103
+ if (!this.host.nativeElement.contains(event.target)) this.hide();
104
+ });
105
+ }
106
+ const pane = this.ref.overlayElement;
107
+ pane.setAttribute("aria-label", this.hoverCardLabel());
108
+ pane.dataset["material"] = this.fidelity.tier() === "low" ? "solid" : "frosted";
109
+ pane.style.visibility = "hidden";
110
+ const strategy = this.ref.getConfig().positionStrategy;
111
+ strategy.withPositions(hyConnectedPositions(this.placement(), 8));
112
+ strategy.positionChanges.pipe(take(1)).subscribe(() => pane.style.removeProperty("visibility"));
113
+ this.open.set(true);
114
+ this.ref.attach(new TemplatePortal(this.content(), this.container));
115
+ }
116
+ hide() {
117
+ clearTimeout(this.timer);
118
+ this.intent.cancel();
119
+ this.open.set(false);
120
+ this.ref?.detach();
121
+ }
122
+ static ɵfac = i0.ɵɵngDeclareFactory({
123
+ minVersion: "12.0.0",
124
+ version: "22.2.3",
125
+ ngImport: i0,
126
+ type: HyHoverCard,
127
+ deps: [],
128
+ target: i0.ɵɵFactoryTarget.Directive
129
+ });
130
+ static ɵdir = i0.ɵɵngDeclareDirective({
131
+ minVersion: "17.1.0",
132
+ version: "22.2.3",
133
+ type: HyHoverCard,
134
+ isStandalone: true,
135
+ selector: "[hyHoverCard]",
136
+ inputs: {
137
+ content: {
138
+ classPropertyName: "content",
139
+ publicName: "hyHoverCard",
140
+ isSignal: true,
141
+ isRequired: true,
142
+ transformFunction: null
143
+ },
144
+ hoverCardLabel: {
145
+ classPropertyName: "hoverCardLabel",
146
+ publicName: "hoverCardLabel",
147
+ isSignal: true,
148
+ isRequired: true,
149
+ transformFunction: null
150
+ },
151
+ placement: {
152
+ classPropertyName: "placement",
153
+ publicName: "placement",
154
+ isSignal: true,
155
+ isRequired: false,
156
+ transformFunction: null
157
+ }
158
+ },
159
+ host: {
160
+ attributes: { "aria-haspopup": "dialog" },
161
+ listeners: {
162
+ "pointerenter": "enter($event)",
163
+ "pointerleave": "leave($event)",
164
+ "focusin": "focusTrigger()",
165
+ "focusout": "focusOut($event)",
166
+ "keydown.escape": "escape($event)",
167
+ "keydown.arrowdown": "focusCard($event)",
168
+ "click": "show()"
169
+ },
170
+ properties: {
171
+ "attr.aria-expanded": "open()",
172
+ "attr.aria-controls": "open()?id:null"
173
+ }
174
+ },
175
+ exportAs: ["hyHoverCard"],
176
+ ngImport: i0
177
+ });
178
+ };
179
+ i0.ɵɵngDeclareClassMetadata({
180
+ minVersion: "12.0.0",
181
+ version: "22.2.3",
182
+ ngImport: i0,
183
+ type: HyHoverCard,
184
+ decorators: [{
185
+ type: Directive,
186
+ args: [{
187
+ selector: "[hyHoverCard]",
188
+ exportAs: "hyHoverCard",
189
+ host: {
190
+ "(pointerenter)": "enter($event)",
191
+ "(pointerleave)": "leave($event)",
192
+ "(focusin)": "focusTrigger()",
193
+ "(focusout)": "focusOut($event)",
194
+ "(keydown.escape)": "escape($event)",
195
+ "(keydown.arrowdown)": "focusCard($event)",
196
+ "(click)": "show()",
197
+ "aria-haspopup": "dialog",
198
+ "[attr.aria-expanded]": "open()",
199
+ "[attr.aria-controls]": "open()?id:null"
200
+ }
201
+ }]
202
+ }],
203
+ ctorParameters: () => [],
204
+ propDecorators: {
205
+ content: [{
206
+ type: i0.Input,
207
+ args: [{
208
+ isSignal: true,
209
+ alias: "hyHoverCard",
210
+ required: true
211
+ }]
212
+ }],
213
+ hoverCardLabel: [{
214
+ type: i0.Input,
215
+ args: [{
216
+ isSignal: true,
217
+ alias: "hoverCardLabel",
218
+ required: true
219
+ }]
220
+ }],
221
+ placement: [{
222
+ type: i0.Input,
223
+ args: [{
224
+ isSignal: true,
225
+ alias: "placement",
226
+ required: false
227
+ }]
228
+ }]
229
+ }
230
+ });
231
+ export { HyHoverCard };
232
+
233
+ //# sourceMappingURL=hyalo-angular-hover-card.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"hyalo-angular-hover-card.mjs","names":[],"sources":["../../../projects/hyalo/hover-card/hover-card.ts"],"sourcesContent":["import { DOCUMENT } from '@angular/common';\r\nimport {\r\n createFlexibleConnectedPositionStrategy,\r\n createOverlayRef,\r\n createRepositionScrollStrategy,\r\n type OverlayRef,\r\n} from '@angular/cdk/overlay';\r\nimport { TemplatePortal } from '@angular/cdk/portal';\r\nimport {\r\n DestroyRef,\r\n Directive,\r\n ElementRef,\r\n Injector,\r\n TemplateRef,\r\n ViewContainerRef,\r\n inject,\r\n input,\r\n signal,\r\n} from '@angular/core';\r\nimport { HyFidelity, injectId } from '@hyalo/angular/core';\r\nimport { HyHoverIntent, hyConnectedPositions, type HyPlacement } from '@hyalo/angular/overlay';\r\nimport { take } from 'rxjs';\r\n@Directive({\r\n selector: '[hyHoverCard]',\r\n exportAs: 'hyHoverCard',\r\n host: {\r\n '(pointerenter)': 'enter($event)',\r\n '(pointerleave)': 'leave($event)',\r\n '(focusin)': 'focusTrigger()',\r\n '(focusout)': 'focusOut($event)',\r\n '(keydown.escape)': 'escape($event)',\r\n '(keydown.arrowdown)': 'focusCard($event)',\r\n '(click)': 'show()',\r\n 'aria-haspopup': 'dialog',\r\n '[attr.aria-expanded]': 'open()',\r\n '[attr.aria-controls]': 'open()?id:null',\r\n },\r\n})\r\nexport class HyHoverCard {\r\n readonly content = input.required<TemplateRef<unknown>>({ alias: 'hyHoverCard' });\r\n readonly hoverCardLabel = input.required<string>();\r\n readonly placement = input<HyPlacement>('top');\r\n readonly open = signal(false);\r\n protected readonly id = injectId('hover-card');\r\n private readonly injector = inject(Injector);\r\n private readonly host = inject<ElementRef<HTMLElement>>(ElementRef);\r\n private readonly container = inject(ViewContainerRef);\r\n private readonly fidelity = inject(HyFidelity);\r\n private readonly document = inject(DOCUMENT);\r\n private readonly intent = new HyHoverIntent(this.document);\r\n private ref: OverlayRef | undefined;\r\n private timer: ReturnType<typeof setTimeout> | undefined;\r\n private disposed = false;\r\n private suppressFocus = false;\r\n protected focusTrigger(): void {\r\n if (!this.suppressFocus) this.show();\r\n }\r\n constructor() {\r\n inject(DestroyRef).onDestroy(() => {\r\n this.disposed = true;\r\n clearTimeout(this.timer);\r\n this.intent.cancel();\r\n this.ref?.dispose();\r\n });\r\n }\r\n protected enter(event: PointerEvent): void {\r\n this.intent.cancel();\r\n if (event.pointerType === 'touch') return;\r\n clearTimeout(this.timer);\r\n this.timer = setTimeout(() => this.show(), 250);\r\n }\r\n protected leave(event?: PointerEvent): void {\r\n clearTimeout(this.timer);\r\n this.intent.leave(event, this.ref?.overlayElement, () => {\r\n if (\r\n this.ref?.overlayElement.contains(this.document.activeElement) ||\r\n this.host.nativeElement.contains(this.document.activeElement)\r\n )\r\n return;\r\n this.hide();\r\n });\r\n }\r\n protected focusOut(event: FocusEvent): void {\r\n if (event.relatedTarget && this.ref?.overlayElement.contains(event.relatedTarget as Node))\r\n return;\r\n this.leave();\r\n }\r\n protected escape(event: Event): void {\r\n if (this.open()) {\r\n event.preventDefault();\r\n event.stopPropagation();\r\n this.hide();\r\n this.suppressFocus = true;\r\n this.host.nativeElement.focus();\r\n this.suppressFocus = false;\r\n }\r\n }\r\n protected focusCard(event: Event): void {\r\n event.preventDefault();\r\n this.show();\r\n const pane = this.ref?.overlayElement;\r\n if (!pane) return;\r\n const focusable = pane.querySelector<HTMLElement>(\r\n 'a[href],button:not([disabled]),input:not([disabled]),[tabindex=\"0\"]',\r\n );\r\n pane.tabIndex = -1;\r\n (focusable ?? pane).focus();\r\n }\r\n show(): void {\r\n clearTimeout(this.timer);\r\n if (this.disposed || this.open()) return;\r\n if (!this.ref) {\r\n const position = createFlexibleConnectedPositionStrategy(this.injector, this.host)\r\n .withPositions(hyConnectedPositions(this.placement(), 8))\r\n .withViewportMargin(12)\r\n .withPush(true);\r\n this.ref = createOverlayRef(this.injector, {\r\n positionStrategy: position,\r\n scrollStrategy: createRepositionScrollStrategy(this.injector),\r\n panelClass: 'hy-hover-card-pane',\r\n });\r\n const pane = this.ref.overlayElement;\r\n pane.classList.add('hy-glass');\r\n pane.style.cssText =\r\n 'max-inline-size:min(22rem,calc(100vw - 2rem));max-block-size:70dvh;overflow:auto;padding:1.25rem;border-radius:var(--hy-radius-m);border:1px solid var(--hy-line-strong);color:var(--hy-ink)';\r\n pane.id = this.id;\r\n pane.setAttribute('role', 'dialog');\r\n pane.addEventListener('pointerenter', () => {\r\n clearTimeout(this.timer);\r\n this.intent.cancel();\r\n });\r\n pane.addEventListener('pointerleave', () => this.leave());\r\n pane.addEventListener('focusout', (event) => {\r\n const next = event.relatedTarget as Node | null;\r\n if (!next || (!pane.contains(next) && !this.host.nativeElement.contains(next)))\r\n this.leave();\r\n });\r\n this.ref.keydownEvents().subscribe((event) => {\r\n if (event.key === 'Escape') this.escape(event);\r\n });\r\n this.ref.outsidePointerEvents().subscribe((event) => {\r\n if (!this.host.nativeElement.contains(event.target as Node)) this.hide();\r\n });\r\n }\r\n const pane = this.ref.overlayElement;\r\n pane.setAttribute('aria-label', this.hoverCardLabel());\r\n pane.dataset['material'] = this.fidelity.tier() === 'low' ? 'solid' : 'frosted';\r\n pane.style.visibility = 'hidden';\r\n const strategy = this.ref.getConfig().positionStrategy as ReturnType<\r\n typeof createFlexibleConnectedPositionStrategy\r\n >;\r\n strategy.withPositions(hyConnectedPositions(this.placement(), 8));\r\n strategy.positionChanges.pipe(take(1)).subscribe(() => pane.style.removeProperty('visibility'));\r\n this.open.set(true);\r\n this.ref.attach(new TemplatePortal(this.content(), this.container));\r\n }\r\n hide(): void {\r\n clearTimeout(this.timer);\r\n this.intent.cancel();\r\n this.open.set(false);\r\n this.ref?.detach();\r\n }\r\n}\r\n"],"mappings":"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"}
@@ -1,6 +1,48 @@
1
1
  import * as i0 from "@angular/core";
2
2
  import { ChangeDetectionStrategy, Component, Directive, ElementRef, Injectable, InjectionToken, Renderer2, computed, effect, inject, input, isDevMode } from "@angular/core";
3
3
  const HY_BUILTIN_ICONS = {
4
+ home: { node: [["path", { d: "m3 10 9-7 9 7v10a1 1 0 0 1-1 1h-5v-7H9v7H4a1 1 0 0 1-1-1Z" }]] },
5
+ grid: { node: [
6
+ ["rect", {
7
+ x: 3,
8
+ y: 3,
9
+ width: 7,
10
+ height: 7,
11
+ rx: 1
12
+ }],
13
+ ["rect", {
14
+ x: 14,
15
+ y: 3,
16
+ width: 7,
17
+ height: 7,
18
+ rx: 1
19
+ }],
20
+ ["rect", {
21
+ x: 3,
22
+ y: 14,
23
+ width: 7,
24
+ height: 7,
25
+ rx: 1
26
+ }],
27
+ ["rect", {
28
+ x: 14,
29
+ y: 14,
30
+ width: 7,
31
+ height: 7,
32
+ rx: 1
33
+ }]
34
+ ] },
35
+ user: { node: [["circle", {
36
+ cx: 12,
37
+ cy: 8,
38
+ r: 4
39
+ }], ["path", { d: "M4 21v-2a7 7 0 0 1 7-7h2a7 7 0 0 1 7 7v2" }]] },
40
+ search: { node: [["circle", {
41
+ cx: 11,
42
+ cy: 11,
43
+ r: 8
44
+ }], ["path", { d: "m21 21-4.35-4.35" }]] },
45
+ settings: { node: [["path", { d: "M12 8a4 4 0 1 0 0 8 4 4 0 0 0 0-8Z" }], ["path", { d: "M9 3h6l1 3 3 1 2 5-2 5-3 1-1 3H9l-1-3-3-1-2-5 2-5 3-1Z" }]] },
4
46
  x: { node: [["path", { d: "M18 6 6 18" }], ["path", { d: "m6 6 12 12" }]] },
5
47
  check: { node: [["path", { d: "M20 6 9 17l-5-5" }]] },
6
48
  minus: { node: [["path", { d: "M5 12h14" }]] },
@@ -1 +1 @@
1
- {"version":3,"file":"hyalo-angular-icon.mjs","names":[],"sources":["../../../projects/hyalo/icon/icons.ts","../../../projects/hyalo/icon/registry.ts","../../../projects/hyalo/icon/icon.ts","../../../projects/hyalo/icon/icon.html"],"sourcesContent":["/**\r\n * Icon data in the same shape Lucide uses (`IconNode`), so any Lucide icon\r\n * can be registered as is:\r\n *\r\n * ```ts\r\n * import { ArrowRight } from 'lucide';\r\n * provideHyaloIcons({ 'arrow-right': ArrowRight })\r\n * ```\r\n *\r\n * Icons are data, not SVG strings, so nothing is ever parsed as HTML.\r\n */\r\nexport type HyIconNode = readonly (readonly [string, Readonly<Record<string, string | number>>])[];\r\n\r\n/** An icon plus how it behaves in right-to-left layouts. */\r\nexport interface HyIconDef {\r\n readonly node: HyIconNode;\r\n /** Mirror the icon in RTL. Set it for icons that point somewhere, like arrows. */\r\n readonly mirrorRtl?: boolean;\r\n}\r\n\r\n/*\r\n * The few icons the kit uses itself. Paths are from Lucide (ISC license,\r\n * Copyright (c) Lucide Icons and Contributors), https://lucide.dev.\r\n */\r\nexport const HY_BUILTIN_ICONS: Readonly<Record<string, HyIconDef>> = {\r\n x: {\r\n node: [\r\n ['path', { d: 'M18 6 6 18' }],\r\n ['path', { d: 'm6 6 12 12' }],\r\n ],\r\n },\r\n check: { node: [['path', { d: 'M20 6 9 17l-5-5' }]] },\r\n minus: { node: [['path', { d: 'M5 12h14' }]] },\r\n 'chevron-down': { node: [['path', { d: 'm6 9 6 6 6-6' }]] },\r\n 'chevron-end': { node: [['path', { d: 'm9 18 6-6-6-6' }]], mirrorRtl: true },\r\n menu: {\r\n node: [\r\n ['path', { d: 'M4 5h16' }],\r\n ['path', { d: 'M4 12h16' }],\r\n ['path', { d: 'M4 19h16' }],\r\n ],\r\n },\r\n info: {\r\n node: [\r\n ['circle', { cx: 12, cy: 12, r: 10 }],\r\n ['path', { d: 'M12 16v-4' }],\r\n ['path', { d: 'M12 8h.01' }],\r\n ],\r\n },\r\n success: {\r\n node: [\r\n ['circle', { cx: 12, cy: 12, r: 10 }],\r\n ['path', { d: 'm16 9-5.5 5.5L8 12' }],\r\n ],\r\n },\r\n warning: {\r\n node: [\r\n ['path', { d: 'm21.73 18-8-14a2 2 0 0 0-3.48 0l-8 14A2 2 0 0 0 4 21h16a2 2 0 0 0 1.73-3' }],\r\n ['path', { d: 'M12 9v4' }],\r\n ['path', { d: 'M12 17h.01' }],\r\n ],\r\n },\r\n danger: {\r\n node: [\r\n ['circle', { cx: 12, cy: 12, r: 10 }],\r\n ['path', { d: 'M12 8v4' }],\r\n ['path', { d: 'M12 16h.01' }],\r\n ],\r\n },\r\n spinner: { node: [['path', { d: 'M21 12a9 9 0 1 1-6.219-8.56' }]] },\r\n};\r\n","import { Injectable, InjectionToken, Provider, inject } from '@angular/core';\r\nimport { HY_BUILTIN_ICONS, type HyIconDef, type HyIconNode } from './icons';\r\n\r\ntype HyIconSet = Readonly<Record<string, HyIconDef | HyIconNode>>;\r\n\r\n/** Icons added with {@link provideHyaloIcons}. Collected from every provider. */\r\nexport const HY_ICONS = new InjectionToken<readonly HyIconSet[]>('HY_ICONS');\r\n\r\n/**\r\n * Registers icons by name. Only the icons you import end up in the bundle.\r\n *\r\n * ```ts\r\n * provideHyaloIcons({ search: Search, 'arrow-end': { node: ArrowRight, mirrorRtl: true } })\r\n * ```\r\n *\r\n * Works in `app.config.ts` and in a route's or component's `providers`.\r\n * Icons from the nearest provider win over app-wide ones.\r\n */\r\nexport function provideHyaloIcons(\r\n icons: Readonly<Record<string, HyIconDef | HyIconNode>>,\r\n): Provider {\r\n return { provide: HY_ICONS, multi: true, useValue: icons };\r\n}\r\n\r\nfunction isDef(value: HyIconDef | HyIconNode): value is HyIconDef {\r\n return !Array.isArray(value);\r\n}\r\n\r\n/** Looks up icons by name: built-ins first, then registered sets in order. */\r\n@Injectable({ providedIn: 'root' })\r\nexport class HyIconRegistry {\r\n private readonly icons = new Map<string, HyIconDef>(Object.entries(HY_BUILTIN_ICONS));\r\n private readonly sets = inject(HY_ICONS, { optional: true }) ?? [];\r\n\r\n constructor() {\r\n for (const set of this.sets) {\r\n for (const [name, icon] of Object.entries(set)) this.register(name, icon);\r\n }\r\n }\r\n\r\n /** Adds or replaces an icon at runtime. */\r\n register(name: string, icon: HyIconDef | HyIconNode): void {\r\n this.icons.set(name, isDef(icon) ? icon : { node: icon });\r\n }\r\n\r\n /** Returns the icon, or undefined when the name is unknown. */\r\n get(name: string): HyIconDef | undefined {\r\n return this.icons.get(name);\r\n }\r\n\r\n /**\r\n * @internal Looks in sets from a route or component injector first. This\r\n * registry lives in the root injector, so it never sees those itself.\r\n */\r\n lookup(name: string, sets: readonly HyIconSet[] | null): HyIconDef | undefined {\r\n if (sets && sets !== this.sets) {\r\n for (const set of [...sets].reverse()) {\r\n const icon = Object.hasOwn(set, name) ? set[name] : undefined;\r\n if (icon) return isDef(icon) ? icon : { node: icon };\r\n }\r\n }\r\n return this.get(name);\r\n }\r\n}\r\n","import {\r\n ChangeDetectionStrategy,\r\n Component,\r\n Directive,\r\n ElementRef,\r\n Renderer2,\r\n computed,\r\n effect,\r\n inject,\r\n input,\r\n isDevMode,\r\n} from '@angular/core';\r\nimport type { HyIconDef, HyIconNode } from './icons';\r\nimport { HY_ICONS, HyIconRegistry } from './registry';\r\n\r\nconst SAFE_ATTRS = new Set([\r\n 'd',\r\n 'cx',\r\n 'cy',\r\n 'r',\r\n 'rx',\r\n 'ry',\r\n 'x',\r\n 'y',\r\n 'x1',\r\n 'x2',\r\n 'y1',\r\n 'y2',\r\n 'width',\r\n 'height',\r\n 'points',\r\n 'fill',\r\n 'stroke',\r\n 'stroke-width',\r\n 'opacity',\r\n 'transform',\r\n]);\r\n\r\n/** Copies whitelisted geometry attributes onto an SVG child element. */\r\n@Directive({ selector: '[hyIconAttrs]' })\r\nexport class HyIconAttrs {\r\n private readonly el = inject(ElementRef).nativeElement as SVGElement;\r\n private readonly renderer = inject(Renderer2);\r\n readonly hyIconAttrs = input.required<Readonly<Record<string, string | number>>>();\r\n\r\n constructor() {\r\n let applied = new Set<string>();\r\n effect(() => {\r\n const next = new Set<string>();\r\n for (const [name, value] of Object.entries(this.hyIconAttrs())) {\r\n if (!SAFE_ATTRS.has(name)) continue;\r\n this.renderer.setAttribute(this.el, name, String(value));\r\n next.add(name);\r\n }\r\n // A swapped icon may not use every attribute the previous one did.\r\n for (const name of applied) {\r\n if (!next.has(name)) this.renderer.removeAttribute(this.el, name);\r\n }\r\n applied = next;\r\n });\r\n }\r\n}\r\n\r\n/**\r\n * An SVG icon from the registry, or passed in directly.\r\n *\r\n * ```html\r\n * <hy-icon name=\"check\" />\r\n * <hy-icon [icon]=\"ArrowRight\" label=\"Next\" />\r\n * ```\r\n *\r\n * Icons are decorative (`aria-hidden`) unless `label` is set, in which case\r\n * they get `role=\"img\"` and that label. The size follows the font size.\r\n */\r\n@Component({\r\n selector: 'hy-icon',\r\n imports: [HyIconAttrs],\r\n changeDetection: ChangeDetectionStrategy.OnPush,\r\n host: {\r\n class: 'hy-icon',\r\n '[attr.role]': 'label() ? \"img\" : null',\r\n '[attr.aria-label]': 'label() || null',\r\n '[attr.aria-hidden]': 'label() ? null : \"true\"',\r\n '[attr.data-mirror-rtl]': 'def()?.mirrorRtl || null',\r\n '[style.--hy-icon-size]': 'size()',\r\n },\r\n templateUrl: './icon.html',\r\n styleUrl: './icon.css',\r\n})\r\nexport class HyIcon {\r\n private readonly registry = inject(HyIconRegistry);\r\n private readonly sets = inject(HY_ICONS, { optional: true });\r\n\r\n /** Registered icon name. */\r\n readonly name = input<string>();\r\n /** Icon data, used instead of `name`. */\r\n readonly icon = input<HyIconDef | HyIconNode>();\r\n /** Accessible name. Leave empty for decorative icons. */\r\n readonly label = input<string>();\r\n /** Any CSS length. Defaults to 1.25em. */\r\n readonly size = input<string>();\r\n /** Stroke width in viewBox units. */\r\n readonly strokeWidth = input(1.75);\r\n\r\n protected readonly def = computed<HyIconDef | undefined>(() => {\r\n const icon = this.icon();\r\n if (icon) return Array.isArray(icon) ? { node: icon as HyIconNode } : (icon as HyIconDef);\r\n const name = this.name();\r\n const found = name ? this.registry.lookup(name, this.sets) : undefined;\r\n if (name && !found && isDevMode()) {\r\n console.warn(`[hyalo] Unknown icon \"${name}\". Register it with provideHyaloIcons().`); // eslint-disable-line no-console\r\n }\r\n return found;\r\n });\r\n}\r\n","<svg\r\n viewBox=\"0 0 24 24\"\r\n fill=\"none\"\r\n stroke=\"currentColor\"\r\n [attr.stroke-width]=\"strokeWidth()\"\r\n stroke-linecap=\"round\"\r\n stroke-linejoin=\"round\"\r\n focusable=\"false\"\r\n>\r\n @for (child of def()?.node; track $index) {\r\n @switch (child[0]) {\r\n @case ('path') {\r\n <svg:path [hyIconAttrs]=\"child[1]\" />\r\n }\r\n @case ('circle') {\r\n <svg:circle [hyIconAttrs]=\"child[1]\" />\r\n }\r\n @case ('line') {\r\n <svg:line [hyIconAttrs]=\"child[1]\" />\r\n }\r\n @case ('rect') {\r\n <svg:rect [hyIconAttrs]=\"child[1]\" />\r\n }\r\n @case ('polyline') {\r\n <svg:polyline [hyIconAttrs]=\"child[1]\" />\r\n }\r\n @case ('polygon') {\r\n <svg:polygon [hyIconAttrs]=\"child[1]\" />\r\n }\r\n @case ('ellipse') {\r\n <svg:ellipse [hyIconAttrs]=\"child[1]\" />\r\n }\r\n }\r\n }\r\n</svg>\r\n"],"mappings":"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"}
1
+ {"version":3,"file":"hyalo-angular-icon.mjs","names":[],"sources":["../../../projects/hyalo/icon/icons.ts","../../../projects/hyalo/icon/registry.ts","../../../projects/hyalo/icon/icon.ts","../../../projects/hyalo/icon/icon.html"],"sourcesContent":["/**\r\n * Icon data in the same shape Lucide uses (`IconNode`), so any Lucide icon\r\n * can be registered as is:\r\n *\r\n * ```ts\r\n * import { ArrowRight } from 'lucide';\r\n * provideHyaloIcons({ 'arrow-right': ArrowRight })\r\n * ```\r\n *\r\n * Icons are data, not SVG strings, so nothing is ever parsed as HTML.\r\n */\r\nexport type HyIconNode = readonly (readonly [string, Readonly<Record<string, string | number>>])[];\r\n\r\n/** An icon plus how it behaves in right-to-left layouts. */\r\nexport interface HyIconDef {\r\n readonly node: HyIconNode;\r\n /** Mirror the icon in RTL. Set it for icons that point somewhere, like arrows. */\r\n readonly mirrorRtl?: boolean;\r\n}\r\n\r\n/*\r\n * The few icons the kit uses itself. Paths are from Lucide (ISC license,\r\n * Copyright (c) Lucide Icons and Contributors), https://lucide.dev.\r\n */\r\nexport const HY_BUILTIN_ICONS: Readonly<Record<string, HyIconDef>> = {\r\n home: { node: [['path', { d: 'm3 10 9-7 9 7v10a1 1 0 0 1-1 1h-5v-7H9v7H4a1 1 0 0 1-1-1Z' }]] },\r\n grid: {\r\n node: [\r\n ['rect', { x: 3, y: 3, width: 7, height: 7, rx: 1 }],\r\n ['rect', { x: 14, y: 3, width: 7, height: 7, rx: 1 }],\r\n ['rect', { x: 3, y: 14, width: 7, height: 7, rx: 1 }],\r\n ['rect', { x: 14, y: 14, width: 7, height: 7, rx: 1 }],\r\n ],\r\n },\r\n user: {\r\n node: [\r\n ['circle', { cx: 12, cy: 8, r: 4 }],\r\n ['path', { d: 'M4 21v-2a7 7 0 0 1 7-7h2a7 7 0 0 1 7 7v2' }],\r\n ],\r\n },\r\n search: {\r\n node: [\r\n ['circle', { cx: 11, cy: 11, r: 8 }],\r\n ['path', { d: 'm21 21-4.35-4.35' }],\r\n ],\r\n },\r\n settings: {\r\n node: [\r\n ['path', { d: 'M12 8a4 4 0 1 0 0 8 4 4 0 0 0 0-8Z' }],\r\n ['path', { d: 'M9 3h6l1 3 3 1 2 5-2 5-3 1-1 3H9l-1-3-3-1-2-5 2-5 3-1Z' }],\r\n ],\r\n },\r\n x: {\r\n node: [\r\n ['path', { d: 'M18 6 6 18' }],\r\n ['path', { d: 'm6 6 12 12' }],\r\n ],\r\n },\r\n check: { node: [['path', { d: 'M20 6 9 17l-5-5' }]] },\r\n minus: { node: [['path', { d: 'M5 12h14' }]] },\r\n 'chevron-down': { node: [['path', { d: 'm6 9 6 6 6-6' }]] },\r\n 'chevron-end': { node: [['path', { d: 'm9 18 6-6-6-6' }]], mirrorRtl: true },\r\n menu: {\r\n node: [\r\n ['path', { d: 'M4 5h16' }],\r\n ['path', { d: 'M4 12h16' }],\r\n ['path', { d: 'M4 19h16' }],\r\n ],\r\n },\r\n info: {\r\n node: [\r\n ['circle', { cx: 12, cy: 12, r: 10 }],\r\n ['path', { d: 'M12 16v-4' }],\r\n ['path', { d: 'M12 8h.01' }],\r\n ],\r\n },\r\n success: {\r\n node: [\r\n ['circle', { cx: 12, cy: 12, r: 10 }],\r\n ['path', { d: 'm16 9-5.5 5.5L8 12' }],\r\n ],\r\n },\r\n warning: {\r\n node: [\r\n ['path', { d: 'm21.73 18-8-14a2 2 0 0 0-3.48 0l-8 14A2 2 0 0 0 4 21h16a2 2 0 0 0 1.73-3' }],\r\n ['path', { d: 'M12 9v4' }],\r\n ['path', { d: 'M12 17h.01' }],\r\n ],\r\n },\r\n danger: {\r\n node: [\r\n ['circle', { cx: 12, cy: 12, r: 10 }],\r\n ['path', { d: 'M12 8v4' }],\r\n ['path', { d: 'M12 16h.01' }],\r\n ],\r\n },\r\n spinner: { node: [['path', { d: 'M21 12a9 9 0 1 1-6.219-8.56' }]] },\r\n};\r\n","import { Injectable, InjectionToken, Provider, inject } from '@angular/core';\r\nimport { HY_BUILTIN_ICONS, type HyIconDef, type HyIconNode } from './icons';\r\n\r\ntype HyIconSet = Readonly<Record<string, HyIconDef | HyIconNode>>;\r\n\r\n/** Icons added with {@link provideHyaloIcons}. Collected from every provider. */\r\nexport const HY_ICONS = new InjectionToken<readonly HyIconSet[]>('HY_ICONS');\r\n\r\n/**\r\n * Registers icons by name. Only the icons you import end up in the bundle.\r\n *\r\n * ```ts\r\n * provideHyaloIcons({ search: Search, 'arrow-end': { node: ArrowRight, mirrorRtl: true } })\r\n * ```\r\n *\r\n * Works in `app.config.ts` and in a route's or component's `providers`.\r\n * Icons from the nearest provider win over app-wide ones.\r\n */\r\nexport function provideHyaloIcons(\r\n icons: Readonly<Record<string, HyIconDef | HyIconNode>>,\r\n): Provider {\r\n return { provide: HY_ICONS, multi: true, useValue: icons };\r\n}\r\n\r\nfunction isDef(value: HyIconDef | HyIconNode): value is HyIconDef {\r\n return !Array.isArray(value);\r\n}\r\n\r\n/** Looks up icons by name: built-ins first, then registered sets in order. */\r\n@Injectable({ providedIn: 'root' })\r\nexport class HyIconRegistry {\r\n private readonly icons = new Map<string, HyIconDef>(Object.entries(HY_BUILTIN_ICONS));\r\n private readonly sets = inject(HY_ICONS, { optional: true }) ?? [];\r\n\r\n constructor() {\r\n for (const set of this.sets) {\r\n for (const [name, icon] of Object.entries(set)) this.register(name, icon);\r\n }\r\n }\r\n\r\n /** Adds or replaces an icon at runtime. */\r\n register(name: string, icon: HyIconDef | HyIconNode): void {\r\n this.icons.set(name, isDef(icon) ? icon : { node: icon });\r\n }\r\n\r\n /** Returns the icon, or undefined when the name is unknown. */\r\n get(name: string): HyIconDef | undefined {\r\n return this.icons.get(name);\r\n }\r\n\r\n /**\r\n * @internal Looks in sets from a route or component injector first. This\r\n * registry lives in the root injector, so it never sees those itself.\r\n */\r\n lookup(name: string, sets: readonly HyIconSet[] | null): HyIconDef | undefined {\r\n if (sets && sets !== this.sets) {\r\n for (const set of [...sets].reverse()) {\r\n const icon = Object.hasOwn(set, name) ? set[name] : undefined;\r\n if (icon) return isDef(icon) ? icon : { node: icon };\r\n }\r\n }\r\n return this.get(name);\r\n }\r\n}\r\n","import {\r\n ChangeDetectionStrategy,\r\n Component,\r\n Directive,\r\n ElementRef,\r\n Renderer2,\r\n computed,\r\n effect,\r\n inject,\r\n input,\r\n isDevMode,\r\n} from '@angular/core';\r\nimport type { HyIconDef, HyIconNode } from './icons';\r\nimport { HY_ICONS, HyIconRegistry } from './registry';\r\n\r\nconst SAFE_ATTRS = new Set([\r\n 'd',\r\n 'cx',\r\n 'cy',\r\n 'r',\r\n 'rx',\r\n 'ry',\r\n 'x',\r\n 'y',\r\n 'x1',\r\n 'x2',\r\n 'y1',\r\n 'y2',\r\n 'width',\r\n 'height',\r\n 'points',\r\n 'fill',\r\n 'stroke',\r\n 'stroke-width',\r\n 'opacity',\r\n 'transform',\r\n]);\r\n\r\n/** Copies whitelisted geometry attributes onto an SVG child element. */\r\n@Directive({ selector: '[hyIconAttrs]' })\r\nexport class HyIconAttrs {\r\n private readonly el = inject(ElementRef).nativeElement as SVGElement;\r\n private readonly renderer = inject(Renderer2);\r\n readonly hyIconAttrs = input.required<Readonly<Record<string, string | number>>>();\r\n\r\n constructor() {\r\n let applied = new Set<string>();\r\n effect(() => {\r\n const next = new Set<string>();\r\n for (const [name, value] of Object.entries(this.hyIconAttrs())) {\r\n if (!SAFE_ATTRS.has(name)) continue;\r\n this.renderer.setAttribute(this.el, name, String(value));\r\n next.add(name);\r\n }\r\n // A swapped icon may not use every attribute the previous one did.\r\n for (const name of applied) {\r\n if (!next.has(name)) this.renderer.removeAttribute(this.el, name);\r\n }\r\n applied = next;\r\n });\r\n }\r\n}\r\n\r\n/**\r\n * An SVG icon from the registry, or passed in directly.\r\n *\r\n * ```html\r\n * <hy-icon name=\"check\" />\r\n * <hy-icon [icon]=\"ArrowRight\" label=\"Next\" />\r\n * ```\r\n *\r\n * Icons are decorative (`aria-hidden`) unless `label` is set, in which case\r\n * they get `role=\"img\"` and that label. The size follows the font size.\r\n */\r\n@Component({\r\n selector: 'hy-icon',\r\n imports: [HyIconAttrs],\r\n changeDetection: ChangeDetectionStrategy.OnPush,\r\n host: {\r\n class: 'hy-icon',\r\n '[attr.role]': 'label() ? \"img\" : null',\r\n '[attr.aria-label]': 'label() || null',\r\n '[attr.aria-hidden]': 'label() ? null : \"true\"',\r\n '[attr.data-mirror-rtl]': 'def()?.mirrorRtl || null',\r\n '[style.--hy-icon-size]': 'size()',\r\n },\r\n templateUrl: './icon.html',\r\n styleUrl: './icon.css',\r\n})\r\nexport class HyIcon {\r\n private readonly registry = inject(HyIconRegistry);\r\n private readonly sets = inject(HY_ICONS, { optional: true });\r\n\r\n /** Registered icon name. */\r\n readonly name = input<string>();\r\n /** Icon data, used instead of `name`. */\r\n readonly icon = input<HyIconDef | HyIconNode>();\r\n /** Accessible name. Leave empty for decorative icons. */\r\n readonly label = input<string>();\r\n /** Any CSS length. Defaults to 1.25em. */\r\n readonly size = input<string>();\r\n /** Stroke width in viewBox units. */\r\n readonly strokeWidth = input(1.75);\r\n\r\n protected readonly def = computed<HyIconDef | undefined>(() => {\r\n const icon = this.icon();\r\n if (icon) return Array.isArray(icon) ? { node: icon as HyIconNode } : (icon as HyIconDef);\r\n const name = this.name();\r\n const found = name ? this.registry.lookup(name, this.sets) : undefined;\r\n if (name && !found && isDevMode()) {\r\n console.warn(`[hyalo] Unknown icon \"${name}\". Register it with provideHyaloIcons().`); // eslint-disable-line no-console\r\n }\r\n return found;\r\n });\r\n}\r\n","<svg\r\n viewBox=\"0 0 24 24\"\r\n fill=\"none\"\r\n stroke=\"currentColor\"\r\n [attr.stroke-width]=\"strokeWidth()\"\r\n stroke-linecap=\"round\"\r\n stroke-linejoin=\"round\"\r\n focusable=\"false\"\r\n>\r\n @for (child of def()?.node; track $index) {\r\n @switch (child[0]) {\r\n @case ('path') {\r\n <svg:path [hyIconAttrs]=\"child[1]\" />\r\n }\r\n @case ('circle') {\r\n <svg:circle [hyIconAttrs]=\"child[1]\" />\r\n }\r\n @case ('line') {\r\n <svg:line [hyIconAttrs]=\"child[1]\" />\r\n }\r\n @case ('rect') {\r\n <svg:rect [hyIconAttrs]=\"child[1]\" />\r\n }\r\n @case ('polyline') {\r\n <svg:polyline [hyIconAttrs]=\"child[1]\" />\r\n }\r\n @case ('polygon') {\r\n <svg:polygon [hyIconAttrs]=\"child[1]\" />\r\n }\r\n @case ('ellipse') {\r\n <svg:ellipse [hyIconAttrs]=\"child[1]\" />\r\n }\r\n }\r\n }\r\n</svg>\r\n"],"mappings":";;AAwBA,MAAa,mBAAwD;CACnE,MAAM,EAAE,MAAM,CAAC,CAAC,QAAQ,EAAE,GAAG,4DAA2D,CAAE,CAAC,EAAC;CAC5F,MAAM,EACJ,MAAM;EACJ,CAAC,QAAQ;GAAE,GAAG;GAAG,GAAG;GAAG,OAAO;GAAG,QAAQ;GAAG,IAAI;EAAC,CAAE;EACnD,CAAC,QAAQ;GAAE,GAAG;GAAI,GAAG;GAAG,OAAO;GAAG,QAAQ;GAAG,IAAI;EAAC,CAAE;EACpD,CAAC,QAAQ;GAAE,GAAG;GAAG,GAAG;GAAI,OAAO;GAAG,QAAQ;GAAG,IAAI;EAAC,CAAE;EACpD,CAAC,QAAQ;GAAE,GAAG;GAAI,GAAG;GAAI,OAAO;GAAG,QAAQ;GAAG,IAAI;EAAC,CAAE;CACtD,EACF;CACD,MAAM,EACJ,MAAM,CACJ,CAAC,UAAU;EAAE,IAAI;EAAI,IAAI;EAAG,GAAG;CAAC,CAAE,GAClC,CAAC,QAAQ,EAAE,GAAG,2CAA0C,CAAE,CAC3D,EACF;CACD,QAAQ,EACN,MAAM,CACJ,CAAC,UAAU;EAAE,IAAI;EAAI,IAAI;EAAI,GAAG;CAAC,CAAE,GACnC,CAAC,QAAQ,EAAE,GAAG,mBAAkB,CAAE,CACnC,EACF;CACD,UAAU,EACR,MAAM,CACJ,CAAC,QAAQ,EAAE,GAAG,qCAAoC,CAAE,GACpD,CAAC,QAAQ,EAAE,GAAG,yDAAwD,CAAE,CACzE,EACF;CACD,GAAG,EACD,MAAM,CACJ,CAAC,QAAQ,EAAE,GAAG,aAAY,CAAE,GAC5B,CAAC,QAAQ,EAAE,GAAG,aAAY,CAAE,CAC7B,EACF;CACD,OAAO,EAAE,MAAM,CAAC,CAAC,QAAQ,EAAE,GAAG,kBAAiB,CAAE,CAAC,EAAC;CACnD,OAAO,EAAE,MAAM,CAAC,CAAC,QAAQ,EAAE,GAAG,WAAU,CAAE,CAAC,EAAC;CAC5C,gBAAgB,EAAE,MAAM,CAAC,CAAC,QAAQ,EAAE,GAAG,eAAc,CAAE,CAAC,EAAC;CACzD,eAAe;EAAE,MAAM,CAAC,CAAC,QAAQ,EAAE,GAAG,gBAAe,CAAE,CAAC;EAAG,WAAW;CAAI;CAC1E,MAAM,EACJ,MAAM;EACJ,CAAC,QAAQ,EAAE,GAAG,UAAS,CAAE;EACzB,CAAC,QAAQ,EAAE,GAAG,WAAU,CAAE;EAC1B,CAAC,QAAQ,EAAE,GAAG,WAAU,CAAE;CAC3B,EACF;CACD,MAAM,EACJ,MAAM;EACJ,CAAC,UAAU;GAAE,IAAI;GAAI,IAAI;GAAI,GAAG;EAAE,CAAE;EACpC,CAAC,QAAQ,EAAE,GAAG,YAAW,CAAE;EAC3B,CAAC,QAAQ,EAAE,GAAG,YAAW,CAAE;CAC5B,EACF;CACD,SAAS,EACP,MAAM,CACJ,CAAC,UAAU;EAAE,IAAI;EAAI,IAAI;EAAI,GAAG;CAAE,CAAE,GACpC,CAAC,QAAQ,EAAE,GAAG,qBAAoB,CAAE,CACrC,EACF;CACD,SAAS,EACP,MAAM;EACJ,CAAC,QAAQ,EAAE,GAAG,2EAA0E,CAAE;EAC1F,CAAC,QAAQ,EAAE,GAAG,UAAS,CAAE;EACzB,CAAC,QAAQ,EAAE,GAAG,aAAY,CAAE;CAC7B,EACF;CACD,QAAQ,EACN,MAAM;EACJ,CAAC,UAAU;GAAE,IAAI;GAAI,IAAI;GAAI,GAAG;EAAE,CAAE;EACpC,CAAC,QAAQ,EAAE,GAAG,UAAS,CAAE;EACzB,CAAC,QAAQ,EAAE,GAAG,aAAY,CAAE;CAC7B,EACF;CACD,SAAS,EAAE,MAAM,CAAC,CAAC,QAAQ,EAAE,GAAG,8BAA6B,CAAE,CAAC,EAAC;AAClE;AC3FD,MAAa,WAAW,IAAI,eAAqC,UAAU;AAY3E,SAAgB,kBACd,OAAuD;CAEvD,OAAO;EAAE,SAAS;EAAU,OAAO;EAAM,UAAU;CAAK;AAC1D;AAEA,SAAS,MAAM,OAA6B;CAC1C,OAAO,CAAC,MAAM,QAAQ,KAAK;AAC7B;AAIA,IAAa,iBAAb,MAAa,eAAc;CACR,QAAQ,IAAI,IAAuB,OAAO,QAAQ,gBAAgB,CAAC;CACnE,OAAO,OAAO,UAAU,EAAE,UAAU,KAAI,CAAE,KAAK,CAAA;CAEhE,cAAA;EACE,KAAK,MAAM,OAAO,KAAK,MACrB,KAAK,MAAM,CAAC,MAAM,SAAS,OAAO,QAAQ,GAAG,GAAG,KAAK,SAAS,MAAM,IAAI;CAE5E;CAGA,SAAS,MAAc,MAA4B;EACjD,KAAK,MAAM,IAAI,MAAM,MAAM,IAAI,IAAI,OAAO,EAAE,MAAM,KAAI,CAAE;CAC1D;CAGA,IAAI,MAAY;EACd,OAAO,KAAK,MAAM,IAAI,IAAI;CAC5B;CAMA,OAAO,MAAc,MAAiC;EACpD,IAAI,QAAQ,SAAS,KAAK,MACxB,KAAK,MAAM,OAAO,CAAC,GAAG,IAAI,CAAC,CAAC,QAAO,GAAI;GACrC,MAAM,OAAO,OAAO,OAAO,KAAK,IAAI,IAAI,IAAI,QAAQ;GACpD,IAAI,MAAM,OAAO,MAAM,IAAI,IAAI,OAAO,EAAE,MAAM,KAAI;EACpD;EAEF,OAAO,KAAK,IAAI,IAAI;CACtB;CAhCW,OAAA,OAAA,GAAA,mBAAA;EAAA,YAAA;EAAA,SAAA;EAAA,UAAA;EAAA,MAAA;EAAc,MAAA,CAAA;EAAA,QAAA,GAAA,gBAAA;CAAA,CAAA;CAAd,OAAA,QAAA,GAAA,sBAAA;EAAA,YAAA;EAAA,SAAA;EAAA,UAAA;EAAA,MAAA;EAAc,YADD;CAAM,CAAA;;AACnB,GAAA,yBAAA;CAAA,YAAA;CAAA,SAAA;CAAA,UAAA;CAAA,MAAA;CAAc,YAAA,CAAA;EAD1B,MAAA;EAAW,MAAA,CAAA,EAAE,YAAY,OAAM,CAAE;;;;ACdlC,MAAM,6BAAa,IAAI,IAAI;CACzB;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;AACD,CAAA;AAID,IAAa,cAAb,MAAa,YAAW;CACL,KAAK,OAAO,UAAU,CAAC,CAAC;CACxB,WAAW,OAAO,SAAS;CACnC,cAAc,MAAM,SAAqD,GAAA,YAAA,CAAA,EAAA,WAAA,cAAA,CAAA,+BAAA,CAAA,CAAA;CAElF,cAAA;EACE,IAAI,0BAAU,IAAI,IAAG;EACrB,aAAY;GACV,MAAM,uBAAO,IAAI,IAAG;GACpB,KAAK,MAAM,CAAC,MAAM,UAAU,OAAO,QAAQ,KAAK,YAAW,CAAE,GAAG;IAC9D,IAAI,CAAC,WAAW,IAAI,IAAI,GAAG;IAC3B,KAAK,SAAS,aAAa,KAAK,IAAI,MAAM,OAAO,KAAK,CAAC;IACvD,KAAK,IAAI,IAAI;GACf;GAEA,KAAK,MAAM,QAAQ,SACjB,IAAI,CAAC,KAAK,IAAI,IAAI,GAAG,KAAK,SAAS,gBAAgB,KAAK,IAAI,IAAI;GAElE,UAAU;EACZ,CAAC;CACH;CApBW,OAAA,OAAA,GAAA,mBAAA;EAAA,YAAA;EAAA,SAAA;EAAA,UAAA;EAAA,MAAA;EAAW,MAAA,CAAA;EAAA,QAAA,GAAA,gBAAA;CAAA,CAAA;CAAX,OAAA,OAAA,GAAA,qBAAA;EAAA,YAAA;EAAA,SAAA;EAAA,MAAA;EAAW,cAAA;EAAA,UAAA;EAAA,QAAA,EAAA,aAAA;GAAA,mBAAA;GAAA,YAAA;GAAA,UAAA;GAAA,YAAA;GAAA,mBAAA;EAAA,EAAA;EAAA,UAAA;CAAA,CAAA;;AAAX,GAAA,yBAAA;CAAA,YAAA;CAAA,SAAA;CAAA,UAAA;CAAA,MAAA;CAAW,YAAA,CAAA;EADvB,MAAA;EAAU,MAAA,CAAA,EAAE,UAAU,gBAAe,CAAE;;;;;;;;;;;;AAkDxC,IAAa,SAAb,MAAa,OAAM;CACA,WAAW,OAAO,cAAc;CAChC,OAAO,OAAO,UAAU,EAAE,UAAU,KAAI,CAAE;CAGlD,OAAO,MAAe,GAAA,YAAA,CAAA,QAAA,EAAA,WAAA,OAAA,CAAA,+BAAA,CAAA,CAAA;CAEtB,OAAO,MAA+B,GAAA,YAAA,CAAA,QAAA,EAAA,WAAA,OAAA,CAAA,+BAAA,CAAA,CAAA;CAEtC,QAAQ,MAAe,GAAA,YAAA,CAAA,QAAA,EAAA,WAAA,QAAA,CAAA,+BAAA,CAAA,CAAA;CAEvB,OAAO,MAAe,GAAA,YAAA,CAAA,QAAA,EAAA,WAAA,OAAA,CAAA,+BAAA,CAAA,CAAA;CAEtB,cAAc,MAAM,MAAK,GAAA,YAAA,CAAA,EAAA,WAAA,cAAA,CAAA,+BAAA,CAAA,CAAA;CAEf,MAAM,eAAqC;EAC5D,MAAM,OAAO,KAAK,KAAI;EACtB,IAAI,MAAM,OAAO,MAAM,QAAQ,IAAI,IAAI,EAAE,MAAM,KAAkB,IAAM;EACvE,MAAM,OAAO,KAAK,KAAI;EACtB,MAAM,QAAQ,OAAO,KAAK,SAAS,OAAO,MAAM,KAAK,IAAI,IAAI;EAC7D,IAAI,QAAQ,CAAC,SAAS,UAAS,GAC7B,QAAQ,KAAK,yBAAyB,KAAI,yCAA0C;EAEtF,OAAO;CACT,GAAE,GAAA,YAAA,CAAA,EAAA,WAAA,MAAA,CAAA,+BAAA,CAAA,CAAA;CAxBS,OAAA,OAAA,GAAA,mBAAA;EAAA,YAAA;EAAA,SAAA;EAAA,UAAA;EAAA,MAAA;EAAM,MAAA,CAAA;EAAA,QAAA,GAAA,gBAAA;CAAA,CAAA;CAAN,OAAA,OAAA,GAAA,qBAAA;EAAA,YAAA;EAAA,SAAA;EAAA,MAAA;EAAM,cAAA;EAAA,UAAA;EAAA,QAAA;GAAA,MAAA;IAAA,mBAAA;IAAA,YAAA;IAAA,UAAA;IAAA,YAAA;IAAA,mBAAA;GAAA;GAAA,MAAA;IAAA,mBAAA;IAAA,YAAA;IAAA,UAAA;IAAA,YAAA;IAAA,mBAAA;GAAA;GAAA,OAAA;IAAA,mBAAA;IAAA,YAAA;IAAA,UAAA;IAAA,YAAA;IAAA,mBAAA;GAAA;GAAA,MAAA;IAAA,mBAAA;IAAA,YAAA;IAAA,UAAA;IAAA,YAAA;IAAA,mBAAA;GAAA;GAAA,aAAA;IAAA,mBAAA;IAAA,YAAA;IAAA,UAAA;IAAA,YAAA;IAAA,mBAAA;GAAA;EAAA;EAAA,MAAA;GAAA,YAAA;IAAA,aAAA;IAAA,mBAAA;IAAA,oBAAA;IAAA,wBAAA;IAAA,wBAAA;GAAA;GAAA,gBAAA;EAAA;EAAA,UAAA;EAAA,UCzFnB;EAmCA,QAAA,CAAA,yPAAA;EAAA,cAAA,CAAA;GAAA,MAAA;GAAA,MDKa;GAAW,UAAA;GAAA,QAAA,CAAA,aAAA;EAAA,CAAA;EAAA,iBAAA,GAAA,wBAAA;CAAA,CAAA;;AAiDX,GAAA,yBAAA;CAAA,YAAA;CAAA,SAAA;CAAA,UAAA;CAAA,MAAA;CAAM,YAAA,CAAA;EAflB,MAAA;EACW,MAAA,CAAA;GAAA,UAAA;GAAS,SACV,CAAC,WAAW;GAAC,iBACL,wBAAwB;GAAM,MACzC;IACJ,OAAO;IACP,eAAe;IACf,qBAAqB;IACrB,sBAAsB;IACtB,0BAA0B;IAC1B,0BAA0B;GAC3B;GAAA,UAAA;GAAA,QAAA,CAAA,yPAAA;EAAA,CAAA"}
@@ -0,0 +1,168 @@
1
+ import * as i0 from "@angular/core";
2
+ import { ChangeDetectionStrategy, Component, computed, input, model } from "@angular/core";
3
+ import { injectId } from "@hyalo/angular/core";
4
+ var HyImageCompare = class HyImageCompare {
5
+ before = input.required(...ngDevMode ? [{ debugName: "before" }] : /* istanbul ignore next */ []);
6
+ after = input.required(...ngDevMode ? [{ debugName: "after" }] : /* istanbul ignore next */ []);
7
+ beforeAlt = input.required(...ngDevMode ? [{ debugName: "beforeAlt" }] : /* istanbul ignore next */ []);
8
+ afterAlt = input.required(...ngDevMode ? [{ debugName: "afterAlt" }] : /* istanbul ignore next */ []);
9
+ label = input("Reveal before image", ...ngDevMode ? [{ debugName: "label" }] : /* istanbul ignore next */ []);
10
+ value = model(50, ...ngDevMode ? [{ debugName: "value" }] : /* istanbul ignore next */ []);
11
+ ratio = input("16 / 9", ...ngDevMode ? [{ debugName: "ratio" }] : /* istanbul ignore next */ []);
12
+ id = injectId("hy-compare");
13
+ position = computed(() => Math.max(0, Math.min(100, Number(this.value()) || 0)), ...ngDevMode ? [{ debugName: "position" }] : /* istanbul ignore next */ []);
14
+ clip = computed(() => "inset(0 " + (100 - this.position()) + "% 0 0)", ...ngDevMode ? [{ debugName: "clip" }] : /* istanbul ignore next */ []);
15
+ change(event) {
16
+ this.value.set(event.target.valueAsNumber);
17
+ }
18
+ static ɵfac = i0.ɵɵngDeclareFactory({
19
+ minVersion: "12.0.0",
20
+ version: "22.2.3",
21
+ ngImport: i0,
22
+ type: HyImageCompare,
23
+ deps: [],
24
+ target: i0.ɵɵFactoryTarget.Component
25
+ });
26
+ static ɵcmp = i0.ɵɵngDeclareComponent({
27
+ minVersion: "17.1.0",
28
+ version: "22.2.3",
29
+ type: HyImageCompare,
30
+ isStandalone: true,
31
+ selector: "hy-image-compare",
32
+ inputs: {
33
+ before: {
34
+ classPropertyName: "before",
35
+ publicName: "before",
36
+ isSignal: true,
37
+ isRequired: true,
38
+ transformFunction: null
39
+ },
40
+ after: {
41
+ classPropertyName: "after",
42
+ publicName: "after",
43
+ isSignal: true,
44
+ isRequired: true,
45
+ transformFunction: null
46
+ },
47
+ beforeAlt: {
48
+ classPropertyName: "beforeAlt",
49
+ publicName: "beforeAlt",
50
+ isSignal: true,
51
+ isRequired: true,
52
+ transformFunction: null
53
+ },
54
+ afterAlt: {
55
+ classPropertyName: "afterAlt",
56
+ publicName: "afterAlt",
57
+ isSignal: true,
58
+ isRequired: true,
59
+ transformFunction: null
60
+ },
61
+ label: {
62
+ classPropertyName: "label",
63
+ publicName: "label",
64
+ isSignal: true,
65
+ isRequired: false,
66
+ transformFunction: null
67
+ },
68
+ value: {
69
+ classPropertyName: "value",
70
+ publicName: "value",
71
+ isSignal: true,
72
+ isRequired: false,
73
+ transformFunction: null
74
+ },
75
+ ratio: {
76
+ classPropertyName: "ratio",
77
+ publicName: "ratio",
78
+ isSignal: true,
79
+ isRequired: false,
80
+ transformFunction: null
81
+ }
82
+ },
83
+ outputs: { value: "valueChange" },
84
+ ngImport: i0,
85
+ template: "<div class=\"frame\" [style.aspect-ratio]=\"ratio()\">\r\n <img [src]=\"after()\" [alt]=\"afterAlt()\" draggable=\"false\" />\r\n <img\r\n class=\"before\"\r\n [src]=\"before()\"\r\n [alt]=\"beforeAlt()\"\r\n [style.clip-path]=\"clip()\"\r\n draggable=\"false\"\r\n />\r\n <span class=\"handle\" aria-hidden=\"true\" [style.left.%]=\"position()\">‖</span>\r\n</div>\r\n<label [for]=\"id\">{{ label() }}: {{ position() }}%</label>\r\n<input\r\n [id]=\"id\"\r\n type=\"range\"\r\n min=\"0\"\r\n max=\"100\"\r\n step=\"1\"\r\n [value]=\"position()\"\r\n (input)=\"change($event)\"\r\n/>\r\n",
86
+ styles: [":host{display:block;color:var(--hy-ink)}.frame{position:relative;overflow:clip;border-radius:var(--hy-radius-l);background:var(--hy-surface-3);direction:ltr}img{position:absolute;inset:0;inline-size:100%;block-size:100%;object-fit:cover}.handle{position:absolute;inset-block:0;inline-size:2px;background:var(--hy-primary-ink);display:grid;place-items:center;color:var(--hy-ink);text-shadow:0 0 3px var(--hy-bg)}label{display:block;margin-block-start:var(--hy-space-3)}input{inline-size:100%;min-block-size:2rem;accent-color:var(--hy-primary);direction:ltr}input:focus-visible{outline:2px solid var(--hy-primary);outline-offset:2px}\n"],
87
+ changeDetection: i0.ChangeDetectionStrategy.OnPush
88
+ });
89
+ };
90
+ i0.ɵɵngDeclareClassMetadata({
91
+ minVersion: "12.0.0",
92
+ version: "22.2.3",
93
+ ngImport: i0,
94
+ type: HyImageCompare,
95
+ decorators: [{
96
+ type: Component,
97
+ args: [{
98
+ selector: "hy-image-compare",
99
+ changeDetection: ChangeDetectionStrategy.OnPush,
100
+ template: "<div class=\"frame\" [style.aspect-ratio]=\"ratio()\">\r\n <img [src]=\"after()\" [alt]=\"afterAlt()\" draggable=\"false\" />\r\n <img\r\n class=\"before\"\r\n [src]=\"before()\"\r\n [alt]=\"beforeAlt()\"\r\n [style.clip-path]=\"clip()\"\r\n draggable=\"false\"\r\n />\r\n <span class=\"handle\" aria-hidden=\"true\" [style.left.%]=\"position()\">‖</span>\r\n</div>\r\n<label [for]=\"id\">{{ label() }}: {{ position() }}%</label>\r\n<input\r\n [id]=\"id\"\r\n type=\"range\"\r\n min=\"0\"\r\n max=\"100\"\r\n step=\"1\"\r\n [value]=\"position()\"\r\n (input)=\"change($event)\"\r\n/>\r\n",
101
+ styles: [":host{display:block;color:var(--hy-ink)}.frame{position:relative;overflow:clip;border-radius:var(--hy-radius-l);background:var(--hy-surface-3);direction:ltr}img{position:absolute;inset:0;inline-size:100%;block-size:100%;object-fit:cover}.handle{position:absolute;inset-block:0;inline-size:2px;background:var(--hy-primary-ink);display:grid;place-items:center;color:var(--hy-ink);text-shadow:0 0 3px var(--hy-bg)}label{display:block;margin-block-start:var(--hy-space-3)}input{inline-size:100%;min-block-size:2rem;accent-color:var(--hy-primary);direction:ltr}input:focus-visible{outline:2px solid var(--hy-primary);outline-offset:2px}\n"]
102
+ }]
103
+ }],
104
+ propDecorators: {
105
+ before: [{
106
+ type: i0.Input,
107
+ args: [{
108
+ isSignal: true,
109
+ alias: "before",
110
+ required: true
111
+ }]
112
+ }],
113
+ after: [{
114
+ type: i0.Input,
115
+ args: [{
116
+ isSignal: true,
117
+ alias: "after",
118
+ required: true
119
+ }]
120
+ }],
121
+ beforeAlt: [{
122
+ type: i0.Input,
123
+ args: [{
124
+ isSignal: true,
125
+ alias: "beforeAlt",
126
+ required: true
127
+ }]
128
+ }],
129
+ afterAlt: [{
130
+ type: i0.Input,
131
+ args: [{
132
+ isSignal: true,
133
+ alias: "afterAlt",
134
+ required: true
135
+ }]
136
+ }],
137
+ label: [{
138
+ type: i0.Input,
139
+ args: [{
140
+ isSignal: true,
141
+ alias: "label",
142
+ required: false
143
+ }]
144
+ }],
145
+ value: [{
146
+ type: i0.Input,
147
+ args: [{
148
+ isSignal: true,
149
+ alias: "value",
150
+ required: false
151
+ }]
152
+ }, {
153
+ type: i0.Output,
154
+ args: ["valueChange"]
155
+ }],
156
+ ratio: [{
157
+ type: i0.Input,
158
+ args: [{
159
+ isSignal: true,
160
+ alias: "ratio",
161
+ required: false
162
+ }]
163
+ }]
164
+ }
165
+ });
166
+ export { HyImageCompare };
167
+
168
+ //# sourceMappingURL=hyalo-angular-image-compare.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"hyalo-angular-image-compare.mjs","names":[],"sources":["../../../projects/hyalo/image-compare/image-compare.ts","../../../projects/hyalo/image-compare/image-compare.html"],"sourcesContent":["import { ChangeDetectionStrategy, Component, computed, input, model } from '@angular/core';\r\nimport { injectId } from '@hyalo/angular/core';\r\n/** Native range input provides pointer, touch, keyboard and screen reader controls. */\r\n@Component({\r\n selector: 'hy-image-compare',\r\n changeDetection: ChangeDetectionStrategy.OnPush,\r\n templateUrl: './image-compare.html',\r\n styleUrl: './image-compare.css',\r\n})\r\nexport class HyImageCompare {\r\n readonly before = input.required<string>();\r\n readonly after = input.required<string>();\r\n readonly beforeAlt = input.required<string>();\r\n readonly afterAlt = input.required<string>();\r\n readonly label = input('Reveal before image');\r\n readonly value = model(50);\r\n readonly ratio = input('16 / 9');\r\n protected readonly id = injectId('hy-compare');\r\n protected readonly position = computed(() =>\r\n Math.max(0, Math.min(100, Number(this.value()) || 0)),\r\n );\r\n protected readonly clip = computed(() => 'inset(0 ' + (100 - this.position()) + '% 0 0)');\r\n protected change(event: Event): void {\r\n this.value.set((event.target as HTMLInputElement).valueAsNumber);\r\n }\r\n}\r\n","<div class=\"frame\" [style.aspect-ratio]=\"ratio()\">\r\n <img [src]=\"after()\" [alt]=\"afterAlt()\" draggable=\"false\" />\r\n <img\r\n class=\"before\"\r\n [src]=\"before()\"\r\n [alt]=\"beforeAlt()\"\r\n [style.clip-path]=\"clip()\"\r\n draggable=\"false\"\r\n />\r\n <span class=\"handle\" aria-hidden=\"true\" [style.left.%]=\"position()\">‖</span>\r\n</div>\r\n<label [for]=\"id\">{{ label() }}: {{ position() }}%</label>\r\n<input\r\n [id]=\"id\"\r\n type=\"range\"\r\n min=\"0\"\r\n max=\"100\"\r\n step=\"1\"\r\n [value]=\"position()\"\r\n (input)=\"change($event)\"\r\n/>\r\n"],"mappings":";;;AASA,IAAa,iBAAb,MAAa,eAAc;CAChB,SAAS,MAAM,SAAkB,GAAA,YAAA,CAAA,EAAA,WAAA,SAAA,CAAA,+BAAA,CAAA,CAAA;CACjC,QAAQ,MAAM,SAAkB,GAAA,YAAA,CAAA,EAAA,WAAA,QAAA,CAAA,+BAAA,CAAA,CAAA;CAChC,YAAY,MAAM,SAAkB,GAAA,YAAA,CAAA,EAAA,WAAA,YAAA,CAAA,+BAAA,CAAA,CAAA;CACpC,WAAW,MAAM,SAAkB,GAAA,YAAA,CAAA,EAAA,WAAA,WAAA,CAAA,+BAAA,CAAA,CAAA;CACnC,QAAQ,MAAM,uBAAsB,GAAA,YAAA,CAAA,EAAA,WAAA,QAAA,CAAA,+BAAA,CAAA,CAAA;CACpC,QAAQ,MAAM,IAAG,GAAA,YAAA,CAAA,EAAA,WAAA,QAAA,CAAA,+BAAA,CAAA,CAAA;CACjB,QAAQ,MAAM,UAAS,GAAA,YAAA,CAAA,EAAA,WAAA,QAAA,CAAA,+BAAA,CAAA,CAAA;CACb,KAAK,SAAS,YAAY;CAC1B,WAAW,eAC5B,KAAK,IAAI,GAAG,KAAK,IAAI,KAAK,OAAO,KAAK,MAAK,CAAE,KAAK,CAAC,CAAC,GACrD,GAAA,YAAA,CAAA,EAAA,WAAA,WAAA,CAAA,+BAAA,CAAA,CAAA;CACkB,OAAO,eAAe,cAAc,MAAM,KAAK,SAAQ,KAAM,UAAS,GAAA,YAAA,CAAA,EAAA,WAAA,OAAA,CAAA,+BAAA,CAAA,CAAA;CAC/E,OAAO,OAAY;EAC3B,KAAK,MAAM,IAAK,MAAM,OAA4B,aAAa;CACjE;CAfW,OAAA,OAAA,GAAA,mBAAA;EAAA,YAAA;EAAA,SAAA;EAAA,UAAA;EAAA,MAAA;EAAc,MAAA,CAAA;EAAA,QAAA,GAAA,gBAAA;CAAA,CAAA;CAAd,OAAA,OAAA,GAAA,qBAAA;EAAA,YAAA;EAAA,SAAA;EAAA,MAAA;EAAc,cAAA;EAAA,UAAA;EAAA,QAAA;GAAA,QAAA;IAAA,mBAAA;IAAA,YAAA;IAAA,UAAA;IAAA,YAAA;IAAA,mBAAA;GAAA;GAAA,OAAA;IAAA,mBAAA;IAAA,YAAA;IAAA,UAAA;IAAA,YAAA;IAAA,mBAAA;GAAA;GAAA,WAAA;IAAA,mBAAA;IAAA,YAAA;IAAA,UAAA;IAAA,YAAA;IAAA,mBAAA;GAAA;GAAA,UAAA;IAAA,mBAAA;IAAA,YAAA;IAAA,UAAA;IAAA,YAAA;IAAA,mBAAA;GAAA;GAAA,OAAA;IAAA,mBAAA;IAAA,YAAA;IAAA,UAAA;IAAA,YAAA;IAAA,mBAAA;GAAA;GAAA,OAAA;IAAA,mBAAA;IAAA,YAAA;IAAA,UAAA;IAAA,YAAA;IAAA,mBAAA;GAAA;GAAA,OAAA;IAAA,mBAAA;IAAA,YAAA;IAAA,UAAA;IAAA,YAAA;IAAA,mBAAA;GAAA;EAAA;EAAA,SAAA,EAAA,OAAA,cAAA;EAAA,UAAA;EAAA,UCT3B;EAqBA,QAAA,CAAA,2nBAAA;EAAA,iBAAA,GAAA,wBAAA;CAAA,CAAA;;ADZa,GAAA,yBAAA;CAAA,YAAA;CAAA,SAAA;CAAA,UAAA;CAAA,MAAA;CAAc,YAAA,CAAA;EAN1B,MAAA;EACW,MAAA,CAAA;GAAA,UAAA;GAAkB,iBACX,wBAAwB;GAAM,UAAA;GAAA,QAAA,CAAA,2nBAAA;EAAA,CAAA"}