@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
@@ -1,14 +1,19 @@
1
+ import { NgTemplateOutlet } from "@angular/common";
1
2
  import * as i0 from "@angular/core";
2
- import { ChangeDetectionStrategy, Component, booleanAttribute, computed, effect, inject, input, model, output, signal, untracked, viewChild } from "@angular/core";
3
+ import { ChangeDetectionStrategy, Component, DOCUMENT, DestroyRef, ElementRef, afterNextRender, booleanAttribute, computed, effect, inject, input, model, output, signal, untracked, viewChild } from "@angular/core";
3
4
  import { Combobox, ComboboxPopup, ComboboxWidget } from "@angular/aria/combobox";
4
5
  import { Listbox, Option } from "@angular/aria/listbox";
5
6
  import { CdkConnectedOverlay, CdkOverlayOrigin } from "@angular/cdk/overlay";
6
- import { HyFidelity, injectId } from "@hyalo/angular";
7
+ import { HyFidelity, injectId } from "@hyalo/angular/core";
7
8
  import { HyIcon } from "@hyalo/angular/icon";
8
9
  import { HY_FIELD } from "@hyalo/angular/field";
9
10
  import { hyDropdownPositions, ɵHyPresence } from "@hyalo/angular/overlay";
10
11
  var HySelect = class HySelect {
11
12
  fidelity = inject(HyFidelity);
13
+ host = inject(ElementRef).nativeElement;
14
+ document = inject(DOCUMENT);
15
+ destroy = inject(DestroyRef);
16
+ ready = signal(false, ...ngDevMode ? [{ debugName: "ready" }] : /* istanbul ignore next */ []);
12
17
  field = inject(HY_FIELD, { optional: true });
13
18
  trigger = viewChild("trigger", ...ngDevMode ? [{ debugName: "trigger" }] : /* istanbul ignore next */ []);
14
19
  overlay = viewChild(CdkConnectedOverlay, ...ngDevMode ? [{ debugName: "overlay" }] : /* istanbul ignore next */ []);
@@ -16,6 +21,8 @@ var HySelect = class HySelect {
16
21
  options = input.required(...ngDevMode ? [{ debugName: "options" }] : /* istanbul ignore next */ []);
17
22
  value = model(void 0, ...ngDevMode ? [{ debugName: "value" }] : /* istanbul ignore next */ []);
18
23
  placeholder = input("Select", ...ngDevMode ? [{ debugName: "placeholder" }] : /* istanbul ignore next */ []);
24
+ name = input("", ...ngDevMode ? [{ debugName: "name" }] : /* istanbul ignore next */ []);
25
+ optionTemplate = input(...ngDevMode ? [void 0, { debugName: "optionTemplate" }] : /* istanbul ignore next */ []);
19
26
  disabled = input(false, {
20
27
  ...ngDevMode ? { debugName: "disabled" } : /* istanbul ignore next */ {},
21
28
  transform: booleanAttribute
@@ -39,7 +46,9 @@ var HySelect = class HySelect {
39
46
  });
40
47
  touch = output();
41
48
  labelable = true;
42
- id = signal(injectId("select")).asReadonly();
49
+ nativeId = injectId("select");
50
+ triggerId = this.nativeId + "-trigger";
51
+ id = computed(() => this.useNative() ? this.nativeId : this.triggerId, ...ngDevMode ? [{ debugName: "id" }] : /* istanbul ignore next */ []);
43
52
  errorMessage = computed(() => {
44
53
  const first = this.errors()[0];
45
54
  return first ? first.message ?? first.kind : void 0;
@@ -48,7 +57,37 @@ var HySelect = class HySelect {
48
57
  rendered = signal(false, ...ngDevMode ? [{ debugName: "rendered" }] : /* istanbul ignore next */ []);
49
58
  positions = hyDropdownPositions();
50
59
  panelWidth = signal(0, ...ngDevMode ? [{ debugName: "panelWidth" }] : /* istanbul ignore next */ []);
51
- useNative = computed(() => this.native() || this.fidelity.tier() === "low", ...ngDevMode ? [{ debugName: "useNative" }] : /* istanbul ignore next */ []);
60
+ useNative = signal(true, ...ngDevMode ? [{ debugName: "useNative" }] : /* istanbul ignore next */ []);
61
+ keyedOptions = computed(() => {
62
+ const keys = /* @__PURE__ */ new Set();
63
+ return this.options().map((option) => {
64
+ const value = option.value;
65
+ if (option.key === void 0 && (typeof value === "object" || typeof value === "function")) throw new Error("HySelect: object values require a stable option key");
66
+ const key = option.key === void 0 ? `${typeof value}:${String(value)}` : `${typeof option.key}:${option.key}`;
67
+ if (keys.has(key)) throw new Error("HySelect: duplicate option key " + key);
68
+ keys.add(key);
69
+ return {
70
+ option,
71
+ key,
72
+ disabled: !!(option.disabled || option.group?.disabled),
73
+ context: { $implicit: option }
74
+ };
75
+ });
76
+ }, ...ngDevMode ? [{ debugName: "keyedOptions" }] : /* istanbul ignore next */ []);
77
+ groups = computed(() => {
78
+ const groups = /* @__PURE__ */ new Map();
79
+ for (const option of this.keyedOptions()) {
80
+ const key = option.option.group?.key ?? "";
81
+ const group = groups.get(key) ?? {
82
+ key,
83
+ label: option.option.group?.label ?? "",
84
+ options: []
85
+ };
86
+ group.options.push(option);
87
+ groups.set(key, group);
88
+ }
89
+ return [...groups.values()];
90
+ }, ...ngDevMode ? [{ debugName: "groups" }] : /* istanbul ignore next */ []);
52
91
  selectedOption = computed(() => this.options().find((o) => o.value === this.value()), ...ngDevMode ? [{ debugName: "selectedOption" }] : /* istanbul ignore next */ []);
53
92
  listValue = computed(() => {
54
93
  const v = this.value();
@@ -56,6 +95,13 @@ var HySelect = class HySelect {
56
95
  }, ...ngDevMode ? [{ debugName: "listValue" }] : /* istanbul ignore next */ []);
57
96
  showsError = computed(() => this.field ? this.field.errorShown() : this.invalid() && this.touched(), ...ngDevMode ? [{ debugName: "showsError" }] : /* istanbul ignore next */ []);
58
97
  constructor() {
98
+ afterNextRender(() => this.ready.set(true));
99
+ effect(() => {
100
+ this.ready();
101
+ this.native();
102
+ this.fidelity.tier();
103
+ this.scheduleMode();
104
+ });
59
105
  effect(() => {
60
106
  const open = this.expanded();
61
107
  untracked(() => {
@@ -101,13 +147,21 @@ var HySelect = class HySelect {
101
147
  this.expanded.set(false);
102
148
  this.trigger()?.nativeElement.focus();
103
149
  }
104
- pickNative(event) {
105
- const index = Number(event.target.value);
106
- const option = this.options()[index];
107
- if (option) this.value.set(option.value);
150
+ scheduleMode() {
151
+ queueMicrotask(() => {
152
+ if (this.destroy.destroyed || !this.ready()) return;
153
+ if (this.expanded() || this.host.contains(this.document.activeElement)) return;
154
+ this.useNative.set(this.native() || this.fidelity.tier() === "low");
155
+ });
108
156
  }
109
- indexOf(value) {
110
- return this.options().findIndex((o) => o.value === value);
157
+ pickNative(event) {
158
+ const key = event.target.value;
159
+ if (!key && !this.required()) {
160
+ this.value.set(void 0);
161
+ return;
162
+ }
163
+ const choice = this.keyedOptions().find((item) => item.key === key);
164
+ if (choice && !choice.disabled) this.value.set(choice.option.value);
111
165
  }
112
166
  static ɵfac = i0.ɵɵngDeclareFactory({
113
167
  minVersion: "12.0.0",
@@ -145,6 +199,20 @@ var HySelect = class HySelect {
145
199
  isRequired: false,
146
200
  transformFunction: null
147
201
  },
202
+ name: {
203
+ classPropertyName: "name",
204
+ publicName: "name",
205
+ isSignal: true,
206
+ isRequired: false,
207
+ transformFunction: null
208
+ },
209
+ optionTemplate: {
210
+ classPropertyName: "optionTemplate",
211
+ publicName: "optionTemplate",
212
+ isSignal: true,
213
+ isRequired: false,
214
+ transformFunction: null
215
+ },
148
216
  disabled: {
149
217
  classPropertyName: "disabled",
150
218
  publicName: "disabled",
@@ -193,6 +261,7 @@ var HySelect = class HySelect {
193
261
  touch: "touch"
194
262
  },
195
263
  host: {
264
+ listeners: { "focusout": "scheduleMode()" },
196
265
  properties: { "attr.data-native": "useNative() || null" },
197
266
  classAttribute: "hy-select"
198
267
  },
@@ -210,9 +279,19 @@ var HySelect = class HySelect {
210
279
  isSignal: true
211
280
  }],
212
281
  ngImport: i0,
213
- template: "@if (useNative()) {\r\n <select\r\n class=\"hy-select__native\"\r\n [id]=\"id()\"\r\n [disabled]=\"disabled()\"\r\n [required]=\"required()\"\r\n [attr.aria-describedby]=\"field?.describedBy() ?? null\"\r\n [attr.aria-invalid]=\"showsError() || null\"\r\n (change)=\"pickNative($event)\"\r\n (blur)=\"touch.emit()\"\r\n >\r\n @if (!selectedOption()) {\r\n <option value=\"\" disabled selected>{{ placeholder() }}</option>\r\n }\r\n @for (option of options(); track $index) {\r\n <option [value]=\"$index\" [selected]=\"option.value === value()\" [disabled]=\"!!option.disabled\">\r\n {{ option.label }}\r\n </option>\r\n }\r\n </select>\r\n <hy-icon class=\"hy-select__chevron\" name=\"chevron-down\" />\r\n} @else {\r\n <button\r\n #trigger\r\n type=\"button\"\r\n ngCombobox\r\n #combobox=\"ngCombobox\"\r\n cdkOverlayOrigin\r\n #origin=\"cdkOverlayOrigin\"\r\n class=\"hy-select__trigger\"\r\n [id]=\"id()\"\r\n [disabled]=\"disabled()\"\r\n [expanded]=\"expanded()\"\r\n (expandedChange)=\"setExpanded($event)\"\r\n [attr.aria-labelledby]=\"field ? field.labelId + ' ' + id() : null\"\r\n [attr.aria-describedby]=\"field?.describedBy() ?? null\"\r\n [attr.aria-invalid]=\"showsError() || null\"\r\n [attr.aria-required]=\"required() || null\"\r\n (blur)=\"touch.emit()\"\r\n >\r\n <span class=\"hy-select__value\" [class.hy-select__placeholder]=\"!selectedOption()\">\r\n {{ selectedOption()?.label ?? placeholder() }}\r\n </span>\r\n <hy-icon class=\"hy-select__chevron\" name=\"chevron-down\" />\r\n </button>\r\n\r\n <ng-template ngComboboxPopup [combobox]=\"combobox\">\r\n <ng-template\r\n cdkConnectedOverlay\r\n [cdkConnectedOverlayOrigin]=\"origin\"\r\n [cdkConnectedOverlayOpen]=\"rendered()\"\r\n [cdkConnectedOverlayPositions]=\"positions\"\r\n [cdkConnectedOverlayMinWidth]=\"panelWidth()\"\r\n cdkConnectedOverlayPanelClass=\"hy-select-overlay\"\r\n cdkConnectedOverlayTransformOriginOn=\".hy-select__panel\"\r\n (attach)=\"onAttach()\"\r\n (overlayOutsideClick)=\"expanded.set(false)\"\r\n >\r\n <!-- Focus stays on the trigger; Aria relays keys here and manages tabindex. -->\r\n <!-- eslint-disable-next-line @angular-eslint/template/interactive-supports-focus -->\r\n <div\r\n ngComboboxWidget\r\n ngListbox\r\n #listbox=\"ngListbox\"\r\n class=\"hy-select__panel hy-glass\"\r\n data-material=\"frosted\"\r\n focusMode=\"activedescendant\"\r\n selectionMode=\"explicit\"\r\n [activeDescendant]=\"listbox.activeDescendant()\"\r\n [value]=\"listValue()\"\r\n (valueChange)=\"pick($event)\"\r\n (click)=\"onPanelClick($event)\"\r\n (keydown.enter)=\"close()\"\r\n (keydown.space)=\"close()\"\r\n >\r\n @for (option of options(); track $index) {\r\n <div\r\n ngOption\r\n class=\"hy-select__option\"\r\n [value]=\"option.value\"\r\n [label]=\"option.label\"\r\n [disabled]=\"!!option.disabled\"\r\n >\r\n <span>{{ option.label }}</span>\r\n <hy-icon class=\"hy-select__check\" name=\"check\" />\r\n </div>\r\n }\r\n </div>\r\n </ng-template>\r\n </ng-template>\r\n}\r\n",
214
- styles: [":host{position:relative;display:flex;align-items:center;flex:1;min-inline-size:0;align-self:stretch}.hy-select__trigger,.hy-select__native{flex:1;min-inline-size:0;align-self:stretch;display:flex;align-items:center;gap:var(--hy-space-2);padding:0;padding-inline-end:1.75rem;border:0;background:transparent;color:var(--hy-ink);font:inherit;text-align:start;cursor:pointer;appearance:none}.hy-select__trigger:focus-visible,.hy-select__native:focus-visible{outline:none}.hy-select__trigger:disabled,.hy-select__native:disabled{cursor:not-allowed}.hy-select__value{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.hy-select__placeholder{color:var(--hy-ink-3)}.hy-select__chevron{position:absolute;inset-inline-end:0;color:var(--hy-ink-3);pointer-events:none;transition:rotate var(--hy-dur-settle) var(--hy-ease-out)}.hy-select__trigger[aria-expanded=true] .hy-select__chevron{rotate:180deg}\n"],
282
+ template: "<select\r\n class=\"hy-select__native\"\r\n [hidden]=\"!useNative()\"\r\n [id]=\"nativeId\"\r\n [disabled]=\"disabled() || !useNative()\"\r\n [required]=\"required()\"\r\n [name]=\"useNative() ? name() : undefined\"\r\n [attr.aria-describedby]=\"field?.describedBy() ?? null\"\r\n [attr.aria-invalid]=\"showsError() || null\"\r\n (change)=\"pickNative($event)\"\r\n (blur)=\"touch.emit()\"\r\n>\r\n <option value=\"\" [disabled]=\"required()\" [selected]=\"!selectedOption()\">\r\n {{ placeholder() }}\r\n </option>\r\n @for (group of groups(); track group.key) {\r\n @if (group.key) {\r\n <optgroup [label]=\"group.label\">\r\n @for (item of group.options; track item.key) {\r\n <option\r\n [value]=\"item.key\"\r\n [selected]=\"item.option.value === value()\"\r\n [disabled]=\"item.disabled\"\r\n >\r\n {{ item.option.label }}\r\n </option>\r\n }\r\n </optgroup>\r\n } @else {\r\n @for (item of group.options; track item.key) {\r\n <option\r\n [value]=\"item.key\"\r\n [selected]=\"item.option.value === value()\"\r\n [disabled]=\"item.disabled\"\r\n >\r\n {{ item.option.label }}\r\n </option>\r\n }\r\n }\r\n }\r\n</select>\r\n<hy-icon [hidden]=\"!useNative()\" class=\"hy-select__chevron\" name=\"chevron-down\" />\r\n<button\r\n #trigger\r\n type=\"button\"\r\n ngCombobox\r\n #combobox=\"ngCombobox\"\r\n cdkOverlayOrigin\r\n #origin=\"cdkOverlayOrigin\"\r\n class=\"hy-select__trigger\"\r\n [hidden]=\"useNative()\"\r\n [id]=\"triggerId\"\r\n [disabled]=\"disabled() || useNative()\"\r\n [expanded]=\"expanded()\"\r\n (expandedChange)=\"setExpanded($event)\"\r\n [attr.aria-labelledby]=\"field ? field.labelId + ' ' + triggerId : null\"\r\n [attr.aria-describedby]=\"field?.describedBy() ?? null\"\r\n [attr.aria-invalid]=\"showsError() || null\"\r\n [attr.aria-required]=\"required() || null\"\r\n (blur)=\"touch.emit()\"\r\n>\r\n <span class=\"hy-select__value\" [class.hy-select__placeholder]=\"!selectedOption()\">{{\r\n selectedOption()?.label ?? placeholder()\r\n }}</span>\r\n <hy-icon class=\"hy-select__chevron\" name=\"chevron-down\" />\r\n</button>\r\n<ng-template ngComboboxPopup [combobox]=\"combobox\">\r\n <ng-template\r\n cdkConnectedOverlay\r\n [cdkConnectedOverlayOrigin]=\"origin\"\r\n [cdkConnectedOverlayOpen]=\"rendered() && !useNative()\"\r\n [cdkConnectedOverlayPositions]=\"positions\"\r\n [cdkConnectedOverlayMinWidth]=\"panelWidth()\"\r\n cdkConnectedOverlayPanelClass=\"hy-select-overlay\"\r\n cdkConnectedOverlayTransformOriginOn=\".hy-select__panel\"\r\n (attach)=\"onAttach()\"\r\n (overlayOutsideClick)=\"expanded.set(false)\"\r\n >\r\n <!-- Focus remains on the combobox trigger while Aria manages the active option. -->\r\n <!-- eslint-disable-next-line @angular-eslint/template/interactive-supports-focus -->\r\n <div\r\n ngComboboxWidget\r\n ngListbox\r\n #listbox=\"ngListbox\"\r\n class=\"hy-select__panel hy-glass\"\r\n data-material=\"frosted\"\r\n focusMode=\"activedescendant\"\r\n selectionMode=\"explicit\"\r\n [activeDescendant]=\"listbox.activeDescendant()\"\r\n [value]=\"listValue()\"\r\n (valueChange)=\"pick($event)\"\r\n (click)=\"onPanelClick($event)\"\r\n (keydown.enter)=\"close()\"\r\n (keydown.space)=\"close()\"\r\n >\r\n @for (group of groups(); track group.key) {\r\n <div role=\"group\" [attr.aria-label]=\"group.label || null\">\r\n @if (group.label) {\r\n <div class=\"hy-select__group-label\">{{ group.label }}</div>\r\n }\r\n @for (item of group.options; track item.key) {\r\n <div\r\n ngOption\r\n class=\"hy-select__option\"\r\n [value]=\"item.option.value\"\r\n [label]=\"item.option.label\"\r\n [disabled]=\"item.disabled\"\r\n >\r\n @if (optionTemplate(); as template) {\r\n <ng-container\r\n [ngTemplateOutlet]=\"template\"\r\n [ngTemplateOutletContext]=\"item.context\"\r\n />\r\n } @else {\r\n <span>{{ item.option.label }}</span>\r\n }\r\n <hy-icon class=\"hy-select__check\" name=\"check\" />\r\n </div>\r\n }\r\n </div>\r\n }\r\n </div>\r\n </ng-template>\r\n</ng-template>\r\n",
283
+ styles: [":host{position:relative;display:flex;align-items:center;flex:1;min-inline-size:0;align-self:stretch}.hy-select__trigger,.hy-select__native{flex:1;min-inline-size:0;align-self:stretch;display:flex;align-items:center;gap:var(--hy-space-2);padding:0;padding-inline-end:1.75rem;border:0;background:transparent;color:var(--hy-ink);font:inherit;text-align:start;cursor:pointer;appearance:none}.hy-select__trigger:focus-visible,.hy-select__native:focus-visible{outline:none}.hy-select__trigger:disabled,.hy-select__native:disabled{cursor:not-allowed}.hy-select__value{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.hy-select__placeholder{color:var(--hy-ink-3)}.hy-select__chevron{--hy-icon-size: 1rem;transform-origin:center;position:absolute;inset-inline-end:0;color:var(--hy-ink-3);pointer-events:none;transition:rotate var(--hy-dur-quick) var(--hy-ease-out)}.hy-select__trigger[aria-expanded=true] .hy-select__chevron{rotate:180deg}[hidden]{display:none!important}.hy-select__group-label{padding:var(--hy-space-2);color:var(--hy-ink-2);font-size:.75rem}@media(prefers-reduced-motion:reduce){.hy-select__chevron{transition:none}}\n"],
215
284
  dependencies: [
285
+ {
286
+ kind: "directive",
287
+ type: NgTemplateOutlet,
288
+ selector: "[ngTemplateOutlet]",
289
+ inputs: [
290
+ "ngTemplateOutletContext",
291
+ "ngTemplateOutlet",
292
+ "ngTemplateOutletInjector"
293
+ ]
294
+ },
216
295
  {
217
296
  kind: "directive",
218
297
  type: Combobox,
@@ -350,6 +429,7 @@ i0.ɵɵngDeclareClassMetadata({
350
429
  args: [{
351
430
  selector: "hy-select",
352
431
  imports: [
432
+ NgTemplateOutlet,
353
433
  Combobox,
354
434
  ComboboxPopup,
355
435
  ComboboxWidget,
@@ -362,10 +442,11 @@ i0.ɵɵngDeclareClassMetadata({
362
442
  changeDetection: ChangeDetectionStrategy.OnPush,
363
443
  host: {
364
444
  class: "hy-select",
365
- "[attr.data-native]": "useNative() || null"
445
+ "[attr.data-native]": "useNative() || null",
446
+ "(focusout)": "scheduleMode()"
366
447
  },
367
- template: "@if (useNative()) {\r\n <select\r\n class=\"hy-select__native\"\r\n [id]=\"id()\"\r\n [disabled]=\"disabled()\"\r\n [required]=\"required()\"\r\n [attr.aria-describedby]=\"field?.describedBy() ?? null\"\r\n [attr.aria-invalid]=\"showsError() || null\"\r\n (change)=\"pickNative($event)\"\r\n (blur)=\"touch.emit()\"\r\n >\r\n @if (!selectedOption()) {\r\n <option value=\"\" disabled selected>{{ placeholder() }}</option>\r\n }\r\n @for (option of options(); track $index) {\r\n <option [value]=\"$index\" [selected]=\"option.value === value()\" [disabled]=\"!!option.disabled\">\r\n {{ option.label }}\r\n </option>\r\n }\r\n </select>\r\n <hy-icon class=\"hy-select__chevron\" name=\"chevron-down\" />\r\n} @else {\r\n <button\r\n #trigger\r\n type=\"button\"\r\n ngCombobox\r\n #combobox=\"ngCombobox\"\r\n cdkOverlayOrigin\r\n #origin=\"cdkOverlayOrigin\"\r\n class=\"hy-select__trigger\"\r\n [id]=\"id()\"\r\n [disabled]=\"disabled()\"\r\n [expanded]=\"expanded()\"\r\n (expandedChange)=\"setExpanded($event)\"\r\n [attr.aria-labelledby]=\"field ? field.labelId + ' ' + id() : null\"\r\n [attr.aria-describedby]=\"field?.describedBy() ?? null\"\r\n [attr.aria-invalid]=\"showsError() || null\"\r\n [attr.aria-required]=\"required() || null\"\r\n (blur)=\"touch.emit()\"\r\n >\r\n <span class=\"hy-select__value\" [class.hy-select__placeholder]=\"!selectedOption()\">\r\n {{ selectedOption()?.label ?? placeholder() }}\r\n </span>\r\n <hy-icon class=\"hy-select__chevron\" name=\"chevron-down\" />\r\n </button>\r\n\r\n <ng-template ngComboboxPopup [combobox]=\"combobox\">\r\n <ng-template\r\n cdkConnectedOverlay\r\n [cdkConnectedOverlayOrigin]=\"origin\"\r\n [cdkConnectedOverlayOpen]=\"rendered()\"\r\n [cdkConnectedOverlayPositions]=\"positions\"\r\n [cdkConnectedOverlayMinWidth]=\"panelWidth()\"\r\n cdkConnectedOverlayPanelClass=\"hy-select-overlay\"\r\n cdkConnectedOverlayTransformOriginOn=\".hy-select__panel\"\r\n (attach)=\"onAttach()\"\r\n (overlayOutsideClick)=\"expanded.set(false)\"\r\n >\r\n <!-- Focus stays on the trigger; Aria relays keys here and manages tabindex. -->\r\n <!-- eslint-disable-next-line @angular-eslint/template/interactive-supports-focus -->\r\n <div\r\n ngComboboxWidget\r\n ngListbox\r\n #listbox=\"ngListbox\"\r\n class=\"hy-select__panel hy-glass\"\r\n data-material=\"frosted\"\r\n focusMode=\"activedescendant\"\r\n selectionMode=\"explicit\"\r\n [activeDescendant]=\"listbox.activeDescendant()\"\r\n [value]=\"listValue()\"\r\n (valueChange)=\"pick($event)\"\r\n (click)=\"onPanelClick($event)\"\r\n (keydown.enter)=\"close()\"\r\n (keydown.space)=\"close()\"\r\n >\r\n @for (option of options(); track $index) {\r\n <div\r\n ngOption\r\n class=\"hy-select__option\"\r\n [value]=\"option.value\"\r\n [label]=\"option.label\"\r\n [disabled]=\"!!option.disabled\"\r\n >\r\n <span>{{ option.label }}</span>\r\n <hy-icon class=\"hy-select__check\" name=\"check\" />\r\n </div>\r\n }\r\n </div>\r\n </ng-template>\r\n </ng-template>\r\n}\r\n",
368
- styles: [":host{position:relative;display:flex;align-items:center;flex:1;min-inline-size:0;align-self:stretch}.hy-select__trigger,.hy-select__native{flex:1;min-inline-size:0;align-self:stretch;display:flex;align-items:center;gap:var(--hy-space-2);padding:0;padding-inline-end:1.75rem;border:0;background:transparent;color:var(--hy-ink);font:inherit;text-align:start;cursor:pointer;appearance:none}.hy-select__trigger:focus-visible,.hy-select__native:focus-visible{outline:none}.hy-select__trigger:disabled,.hy-select__native:disabled{cursor:not-allowed}.hy-select__value{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.hy-select__placeholder{color:var(--hy-ink-3)}.hy-select__chevron{position:absolute;inset-inline-end:0;color:var(--hy-ink-3);pointer-events:none;transition:rotate var(--hy-dur-settle) var(--hy-ease-out)}.hy-select__trigger[aria-expanded=true] .hy-select__chevron{rotate:180deg}\n"]
448
+ template: "<select\r\n class=\"hy-select__native\"\r\n [hidden]=\"!useNative()\"\r\n [id]=\"nativeId\"\r\n [disabled]=\"disabled() || !useNative()\"\r\n [required]=\"required()\"\r\n [name]=\"useNative() ? name() : undefined\"\r\n [attr.aria-describedby]=\"field?.describedBy() ?? null\"\r\n [attr.aria-invalid]=\"showsError() || null\"\r\n (change)=\"pickNative($event)\"\r\n (blur)=\"touch.emit()\"\r\n>\r\n <option value=\"\" [disabled]=\"required()\" [selected]=\"!selectedOption()\">\r\n {{ placeholder() }}\r\n </option>\r\n @for (group of groups(); track group.key) {\r\n @if (group.key) {\r\n <optgroup [label]=\"group.label\">\r\n @for (item of group.options; track item.key) {\r\n <option\r\n [value]=\"item.key\"\r\n [selected]=\"item.option.value === value()\"\r\n [disabled]=\"item.disabled\"\r\n >\r\n {{ item.option.label }}\r\n </option>\r\n }\r\n </optgroup>\r\n } @else {\r\n @for (item of group.options; track item.key) {\r\n <option\r\n [value]=\"item.key\"\r\n [selected]=\"item.option.value === value()\"\r\n [disabled]=\"item.disabled\"\r\n >\r\n {{ item.option.label }}\r\n </option>\r\n }\r\n }\r\n }\r\n</select>\r\n<hy-icon [hidden]=\"!useNative()\" class=\"hy-select__chevron\" name=\"chevron-down\" />\r\n<button\r\n #trigger\r\n type=\"button\"\r\n ngCombobox\r\n #combobox=\"ngCombobox\"\r\n cdkOverlayOrigin\r\n #origin=\"cdkOverlayOrigin\"\r\n class=\"hy-select__trigger\"\r\n [hidden]=\"useNative()\"\r\n [id]=\"triggerId\"\r\n [disabled]=\"disabled() || useNative()\"\r\n [expanded]=\"expanded()\"\r\n (expandedChange)=\"setExpanded($event)\"\r\n [attr.aria-labelledby]=\"field ? field.labelId + ' ' + triggerId : null\"\r\n [attr.aria-describedby]=\"field?.describedBy() ?? null\"\r\n [attr.aria-invalid]=\"showsError() || null\"\r\n [attr.aria-required]=\"required() || null\"\r\n (blur)=\"touch.emit()\"\r\n>\r\n <span class=\"hy-select__value\" [class.hy-select__placeholder]=\"!selectedOption()\">{{\r\n selectedOption()?.label ?? placeholder()\r\n }}</span>\r\n <hy-icon class=\"hy-select__chevron\" name=\"chevron-down\" />\r\n</button>\r\n<ng-template ngComboboxPopup [combobox]=\"combobox\">\r\n <ng-template\r\n cdkConnectedOverlay\r\n [cdkConnectedOverlayOrigin]=\"origin\"\r\n [cdkConnectedOverlayOpen]=\"rendered() && !useNative()\"\r\n [cdkConnectedOverlayPositions]=\"positions\"\r\n [cdkConnectedOverlayMinWidth]=\"panelWidth()\"\r\n cdkConnectedOverlayPanelClass=\"hy-select-overlay\"\r\n cdkConnectedOverlayTransformOriginOn=\".hy-select__panel\"\r\n (attach)=\"onAttach()\"\r\n (overlayOutsideClick)=\"expanded.set(false)\"\r\n >\r\n <!-- Focus remains on the combobox trigger while Aria manages the active option. -->\r\n <!-- eslint-disable-next-line @angular-eslint/template/interactive-supports-focus -->\r\n <div\r\n ngComboboxWidget\r\n ngListbox\r\n #listbox=\"ngListbox\"\r\n class=\"hy-select__panel hy-glass\"\r\n data-material=\"frosted\"\r\n focusMode=\"activedescendant\"\r\n selectionMode=\"explicit\"\r\n [activeDescendant]=\"listbox.activeDescendant()\"\r\n [value]=\"listValue()\"\r\n (valueChange)=\"pick($event)\"\r\n (click)=\"onPanelClick($event)\"\r\n (keydown.enter)=\"close()\"\r\n (keydown.space)=\"close()\"\r\n >\r\n @for (group of groups(); track group.key) {\r\n <div role=\"group\" [attr.aria-label]=\"group.label || null\">\r\n @if (group.label) {\r\n <div class=\"hy-select__group-label\">{{ group.label }}</div>\r\n }\r\n @for (item of group.options; track item.key) {\r\n <div\r\n ngOption\r\n class=\"hy-select__option\"\r\n [value]=\"item.option.value\"\r\n [label]=\"item.option.label\"\r\n [disabled]=\"item.disabled\"\r\n >\r\n @if (optionTemplate(); as template) {\r\n <ng-container\r\n [ngTemplateOutlet]=\"template\"\r\n [ngTemplateOutletContext]=\"item.context\"\r\n />\r\n } @else {\r\n <span>{{ item.option.label }}</span>\r\n }\r\n <hy-icon class=\"hy-select__check\" name=\"check\" />\r\n </div>\r\n }\r\n </div>\r\n }\r\n </div>\r\n </ng-template>\r\n</ng-template>\r\n",
449
+ styles: [":host{position:relative;display:flex;align-items:center;flex:1;min-inline-size:0;align-self:stretch}.hy-select__trigger,.hy-select__native{flex:1;min-inline-size:0;align-self:stretch;display:flex;align-items:center;gap:var(--hy-space-2);padding:0;padding-inline-end:1.75rem;border:0;background:transparent;color:var(--hy-ink);font:inherit;text-align:start;cursor:pointer;appearance:none}.hy-select__trigger:focus-visible,.hy-select__native:focus-visible{outline:none}.hy-select__trigger:disabled,.hy-select__native:disabled{cursor:not-allowed}.hy-select__value{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.hy-select__placeholder{color:var(--hy-ink-3)}.hy-select__chevron{--hy-icon-size: 1rem;transform-origin:center;position:absolute;inset-inline-end:0;color:var(--hy-ink-3);pointer-events:none;transition:rotate var(--hy-dur-quick) var(--hy-ease-out)}.hy-select__trigger[aria-expanded=true] .hy-select__chevron{rotate:180deg}[hidden]{display:none!important}.hy-select__group-label{padding:var(--hy-space-2);color:var(--hy-ink-2);font-size:.75rem}@media(prefers-reduced-motion:reduce){.hy-select__chevron{transition:none}}\n"]
369
450
  }]
370
451
  }],
371
452
  ctorParameters: () => [],
@@ -405,6 +486,22 @@ i0.ɵɵngDeclareClassMetadata({
405
486
  required: false
406
487
  }]
407
488
  }],
489
+ name: [{
490
+ type: i0.Input,
491
+ args: [{
492
+ isSignal: true,
493
+ alias: "name",
494
+ required: false
495
+ }]
496
+ }],
497
+ optionTemplate: [{
498
+ type: i0.Input,
499
+ args: [{
500
+ isSignal: true,
501
+ alias: "optionTemplate",
502
+ required: false
503
+ }]
504
+ }],
408
505
  disabled: [{
409
506
  type: i0.Input,
410
507
  args: [{
@@ -1 +1 @@
1
- {"version":3,"file":"hyalo-angular-select.mjs","names":["HyPresence"],"sources":["../../../projects/hyalo/select/select.ts","../../../projects/hyalo/select/select.html"],"sourcesContent":["import {\r\n ChangeDetectionStrategy,\r\n Component,\r\n ElementRef,\r\n booleanAttribute,\r\n computed,\r\n effect,\r\n inject,\r\n input,\r\n model,\r\n output,\r\n signal,\r\n untracked,\r\n viewChild,\r\n} from '@angular/core';\r\nimport { Combobox, ComboboxPopup, ComboboxWidget } from '@angular/aria/combobox';\r\nimport { Listbox, Option } from '@angular/aria/listbox';\r\nimport { CdkConnectedOverlay, CdkOverlayOrigin } from '@angular/cdk/overlay';\r\nimport type { FormValueControl } from '@angular/forms/signals';\r\nimport { HyFidelity, injectId } from '@hyalo/angular';\r\nimport { HyIcon } from '@hyalo/angular/icon';\r\nimport { HY_FIELD, type HyFieldControl } from '@hyalo/angular/field';\r\nimport { hyDropdownPositions, ɵHyPresence as HyPresence } from '@hyalo/angular/overlay';\r\n\r\n/** One choice in a select. */\r\nexport interface HySelectOption<T> {\r\n readonly value: T;\r\n readonly label: string;\r\n readonly disabled?: boolean;\r\n}\r\n\r\n/**\r\n * A single-choice select with a glass dropdown, built on Angular Aria's\r\n * combobox and listbox patterns.\r\n *\r\n * ```html\r\n * <hy-field label=\"Strap\">\r\n * <hy-select [options]=\"straps\" [formField]=\"form.strap\" placeholder=\"Choose a strap\" />\r\n * </hy-field>\r\n * ```\r\n *\r\n * Focus stays on the trigger while the list is open, and options are\r\n * announced through `aria-activedescendant`. Arrow keys move, Enter or\r\n * Space picks, Escape closes, and typing jumps to a matching option.\r\n *\r\n * On the low fidelity tier, or with `native`, it renders a real `<select>`\r\n * instead. That gives the platform picker on phones and costs nothing.\r\n */\r\n@Component({\r\n selector: 'hy-select',\r\n imports: [\r\n Combobox,\r\n ComboboxPopup,\r\n ComboboxWidget,\r\n Listbox,\r\n Option,\r\n CdkConnectedOverlay,\r\n CdkOverlayOrigin,\r\n HyIcon,\r\n ],\r\n changeDetection: ChangeDetectionStrategy.OnPush,\r\n host: {\r\n class: 'hy-select',\r\n '[attr.data-native]': 'useNative() || null',\r\n },\r\n templateUrl: './select.html',\r\n styleUrl: './select.css',\r\n})\r\nexport class HySelect<T> implements FormValueControl<T | undefined>, HyFieldControl {\r\n private readonly fidelity = inject(HyFidelity);\r\n protected readonly field = inject(HY_FIELD, { optional: true });\r\n private readonly trigger = viewChild<ElementRef<HTMLElement>>('trigger');\r\n private readonly overlay = viewChild(CdkConnectedOverlay);\r\n private readonly presence = new HyPresence();\r\n\r\n /** The choices. */\r\n readonly options = input.required<readonly HySelectOption<T>[]>();\r\n /** Selected value. Two-way bindable and works with `[formField]`. */\r\n readonly value = model<T | undefined>(undefined);\r\n /** Text shown while nothing is selected. */\r\n readonly placeholder = input('Select');\r\n /** Disables the select. Set automatically by Signal Forms. */\r\n readonly disabled = input(false, { transform: booleanAttribute });\r\n /** Marks the field as required. Set automatically by Signal Forms. */\r\n readonly required = input(false, { transform: booleanAttribute });\r\n /** Set by Signal Forms. */\r\n readonly invalid = input(false, { transform: booleanAttribute });\r\n /** Set by Signal Forms. Only the first message is shown. */\r\n readonly errors = input<readonly { readonly kind: string; readonly message?: string }[]>([]);\r\n /** Set by Signal Forms. Errors show only after the field is touched. */\r\n readonly touched = input(false, { transform: booleanAttribute });\r\n /** Always render a native `<select>`. */\r\n readonly native = input(false, { transform: booleanAttribute });\r\n /** Emits when the control loses focus, so forms can mark it touched. */\r\n readonly touch = output<void>();\r\n\r\n readonly labelable = true;\r\n readonly id = signal(injectId('select')).asReadonly();\r\n readonly errorMessage = computed(() => {\r\n const first = this.errors()[0];\r\n return first ? (first.message ?? first.kind) : undefined;\r\n });\r\n\r\n protected readonly expanded = signal(false);\r\n /** Stays true while the panel fades out after `expanded` turns false. */\r\n protected readonly rendered = signal(false);\r\n protected readonly positions = hyDropdownPositions();\r\n protected readonly panelWidth = signal(0);\r\n protected readonly useNative = computed(() => this.native() || this.fidelity.tier() === 'low');\r\n protected readonly selectedOption = computed(() =>\r\n this.options().find((o) => o.value === this.value()),\r\n );\r\n protected readonly listValue = computed(() => {\r\n const v = this.value();\r\n return v === undefined ? [] : [v];\r\n });\r\n protected readonly showsError = computed(() =>\r\n this.field ? this.field.errorShown() : this.invalid() && this.touched(),\r\n );\r\n\r\n constructor() {\r\n effect(() => {\r\n const open = this.expanded();\r\n untracked(() => {\r\n const panel = this.panelElement();\r\n if (open) {\r\n // Reopened while fading out: turn the exit around.\r\n if (panel && this.presence.leaving) this.presence.enter(panel);\r\n this.rendered.set(true);\r\n } else if (panel) {\r\n this.presence.leave(panel, () => this.rendered.set(false));\r\n } else {\r\n this.rendered.set(false);\r\n }\r\n });\r\n });\r\n this.field?.register({\r\n id: this.id,\r\n invalid: computed(() => this.invalid() && this.touched()),\r\n errorMessage: this.errorMessage,\r\n required: this.required,\r\n disabled: this.disabled,\r\n labelable: true,\r\n });\r\n }\r\n\r\n protected setExpanded(open: boolean): void {\r\n if (open) this.panelWidth.set(this.trigger()?.nativeElement.offsetWidth ?? 0);\r\n this.expanded.set(open);\r\n }\r\n\r\n /** Runs when the overlay attaches a fresh panel. */\r\n protected onAttach(): void {\r\n const panel = this.panelElement();\r\n if (panel) this.presence.enter(panel);\r\n }\r\n\r\n private panelElement(): HTMLElement | null {\r\n return (\r\n this.overlay()?.overlayRef?.overlayElement.querySelector<HTMLElement>('.hy-select__panel') ??\r\n null\r\n );\r\n }\r\n\r\n protected pick(values: readonly T[]): void {\r\n const next = values[values.length - 1];\r\n if (next === undefined || next === this.value()) return;\r\n this.value.set(next);\r\n this.close();\r\n }\r\n\r\n /** Closes after a click on an option, including the one already selected. */\r\n protected onPanelClick(event: MouseEvent): void {\r\n const option = (event.target as Element | null)?.closest('[role=\"option\"]');\r\n if (option && option.getAttribute('aria-disabled') !== 'true') this.close();\r\n }\r\n\r\n protected close(): void {\r\n this.expanded.set(false);\r\n this.trigger()?.nativeElement.focus();\r\n }\r\n\r\n protected pickNative(event: Event): void {\r\n const index = Number((event.target as HTMLSelectElement).value);\r\n const option = this.options()[index];\r\n if (option) this.value.set(option.value);\r\n }\r\n\r\n protected indexOf(value: T | undefined): number {\r\n return this.options().findIndex((o) => o.value === value);\r\n }\r\n}\r\n","@if (useNative()) {\r\n <select\r\n class=\"hy-select__native\"\r\n [id]=\"id()\"\r\n [disabled]=\"disabled()\"\r\n [required]=\"required()\"\r\n [attr.aria-describedby]=\"field?.describedBy() ?? null\"\r\n [attr.aria-invalid]=\"showsError() || null\"\r\n (change)=\"pickNative($event)\"\r\n (blur)=\"touch.emit()\"\r\n >\r\n @if (!selectedOption()) {\r\n <option value=\"\" disabled selected>{{ placeholder() }}</option>\r\n }\r\n @for (option of options(); track $index) {\r\n <option [value]=\"$index\" [selected]=\"option.value === value()\" [disabled]=\"!!option.disabled\">\r\n {{ option.label }}\r\n </option>\r\n }\r\n </select>\r\n <hy-icon class=\"hy-select__chevron\" name=\"chevron-down\" />\r\n} @else {\r\n <button\r\n #trigger\r\n type=\"button\"\r\n ngCombobox\r\n #combobox=\"ngCombobox\"\r\n cdkOverlayOrigin\r\n #origin=\"cdkOverlayOrigin\"\r\n class=\"hy-select__trigger\"\r\n [id]=\"id()\"\r\n [disabled]=\"disabled()\"\r\n [expanded]=\"expanded()\"\r\n (expandedChange)=\"setExpanded($event)\"\r\n [attr.aria-labelledby]=\"field ? field.labelId + ' ' + id() : null\"\r\n [attr.aria-describedby]=\"field?.describedBy() ?? null\"\r\n [attr.aria-invalid]=\"showsError() || null\"\r\n [attr.aria-required]=\"required() || null\"\r\n (blur)=\"touch.emit()\"\r\n >\r\n <span class=\"hy-select__value\" [class.hy-select__placeholder]=\"!selectedOption()\">\r\n {{ selectedOption()?.label ?? placeholder() }}\r\n </span>\r\n <hy-icon class=\"hy-select__chevron\" name=\"chevron-down\" />\r\n </button>\r\n\r\n <ng-template ngComboboxPopup [combobox]=\"combobox\">\r\n <ng-template\r\n cdkConnectedOverlay\r\n [cdkConnectedOverlayOrigin]=\"origin\"\r\n [cdkConnectedOverlayOpen]=\"rendered()\"\r\n [cdkConnectedOverlayPositions]=\"positions\"\r\n [cdkConnectedOverlayMinWidth]=\"panelWidth()\"\r\n cdkConnectedOverlayPanelClass=\"hy-select-overlay\"\r\n cdkConnectedOverlayTransformOriginOn=\".hy-select__panel\"\r\n (attach)=\"onAttach()\"\r\n (overlayOutsideClick)=\"expanded.set(false)\"\r\n >\r\n <!-- Focus stays on the trigger; Aria relays keys here and manages tabindex. -->\r\n <!-- eslint-disable-next-line @angular-eslint/template/interactive-supports-focus -->\r\n <div\r\n ngComboboxWidget\r\n ngListbox\r\n #listbox=\"ngListbox\"\r\n class=\"hy-select__panel hy-glass\"\r\n data-material=\"frosted\"\r\n focusMode=\"activedescendant\"\r\n selectionMode=\"explicit\"\r\n [activeDescendant]=\"listbox.activeDescendant()\"\r\n [value]=\"listValue()\"\r\n (valueChange)=\"pick($event)\"\r\n (click)=\"onPanelClick($event)\"\r\n (keydown.enter)=\"close()\"\r\n (keydown.space)=\"close()\"\r\n >\r\n @for (option of options(); track $index) {\r\n <div\r\n ngOption\r\n class=\"hy-select__option\"\r\n [value]=\"option.value\"\r\n [label]=\"option.label\"\r\n [disabled]=\"!!option.disabled\"\r\n >\r\n <span>{{ option.label }}</span>\r\n <hy-icon class=\"hy-select__check\" name=\"check\" />\r\n </div>\r\n }\r\n </div>\r\n </ng-template>\r\n </ng-template>\r\n}\r\n"],"mappings":"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"}
1
+ {"version":3,"file":"hyalo-angular-select.mjs","names":["HyPresence"],"sources":["../../../projects/hyalo/select/select.ts","../../../projects/hyalo/select/select.html"],"sourcesContent":["import { NgTemplateOutlet } from '@angular/common';\r\nimport {\r\n ChangeDetectionStrategy,\r\n Component,\r\n DOCUMENT,\r\n DestroyRef,\r\n TemplateRef,\r\n afterNextRender,\r\n ElementRef,\r\n booleanAttribute,\r\n computed,\r\n effect,\r\n inject,\r\n input,\r\n model,\r\n output,\r\n signal,\r\n untracked,\r\n viewChild,\r\n} from '@angular/core';\r\nimport { Combobox, ComboboxPopup, ComboboxWidget } from '@angular/aria/combobox';\r\nimport { Listbox, Option } from '@angular/aria/listbox';\r\nimport { CdkConnectedOverlay, CdkOverlayOrigin } from '@angular/cdk/overlay';\r\nimport type { FormValueControl } from '@angular/forms/signals';\r\nimport { HyFidelity, injectId } from '@hyalo/angular/core';\r\nimport { HyIcon } from '@hyalo/angular/icon';\r\nimport { HY_FIELD, type HyFieldControl } from '@hyalo/angular/field';\r\nimport { hyDropdownPositions, ɵHyPresence as HyPresence } from '@hyalo/angular/overlay';\r\n\r\n/** One choice in a select. */\r\nexport interface HySelectOption<T> {\r\n readonly key?: string | number;\r\n readonly group?: { readonly key: string; readonly label: string; readonly disabled?: boolean };\r\n readonly value: T;\r\n readonly label: string;\r\n readonly disabled?: boolean;\r\n}\r\n\r\nexport interface HySelectOptionContext<T> {\r\n readonly $implicit: HySelectOption<T>;\r\n}\r\n\r\n/**\r\n * A single-choice select with a glass dropdown, built on Angular Aria's\r\n * combobox and listbox patterns.\r\n *\r\n * ```html\r\n * <hy-field label=\"Strap\">\r\n * <hy-select [options]=\"straps\" [formField]=\"form.strap\" placeholder=\"Choose a strap\" />\r\n * </hy-field>\r\n * ```\r\n *\r\n * Focus stays on the trigger while the list is open, and options are\r\n * announced through `aria-activedescendant`. Arrow keys move, Enter or\r\n * Space picks, Escape closes, and typing jumps to a matching option.\r\n *\r\n * On the low fidelity tier, or with `native`, it renders a real `<select>`\r\n * instead. That gives the platform picker on phones and costs nothing.\r\n */\r\n@Component({\r\n selector: 'hy-select',\r\n imports: [\r\n NgTemplateOutlet,\r\n Combobox,\r\n ComboboxPopup,\r\n ComboboxWidget,\r\n Listbox,\r\n Option,\r\n CdkConnectedOverlay,\r\n CdkOverlayOrigin,\r\n HyIcon,\r\n ],\r\n changeDetection: ChangeDetectionStrategy.OnPush,\r\n host: {\r\n class: 'hy-select',\r\n '[attr.data-native]': 'useNative() || null',\r\n '(focusout)': 'scheduleMode()',\r\n },\r\n templateUrl: './select.html',\r\n styleUrl: './select.css',\r\n})\r\nexport class HySelect<T> implements FormValueControl<T | undefined>, HyFieldControl {\r\n private readonly fidelity = inject(HyFidelity);\r\n private readonly host = inject<ElementRef<HTMLElement>>(ElementRef).nativeElement;\r\n private readonly document = inject(DOCUMENT);\r\n private readonly destroy = inject(DestroyRef);\r\n private readonly ready = signal(false);\r\n protected readonly field = inject(HY_FIELD, { optional: true });\r\n private readonly trigger = viewChild<ElementRef<HTMLElement>>('trigger');\r\n private readonly overlay = viewChild(CdkConnectedOverlay);\r\n private readonly presence = new HyPresence();\r\n\r\n /** The choices. */\r\n readonly options = input.required<readonly HySelectOption<T>[]>();\r\n /** Selected value. Two-way bindable and works with `[formField]`. */\r\n readonly value = model<T | undefined>(undefined);\r\n /** Text shown while nothing is selected. */\r\n readonly placeholder = input('Select');\r\n readonly name = input('');\r\n readonly optionTemplate = input<TemplateRef<HySelectOptionContext<T>>>();\r\n /** Disables the select. Set automatically by Signal Forms. */\r\n readonly disabled = input(false, { transform: booleanAttribute });\r\n /** Marks the field as required. Set automatically by Signal Forms. */\r\n readonly required = input(false, { transform: booleanAttribute });\r\n /** Set by Signal Forms. */\r\n readonly invalid = input(false, { transform: booleanAttribute });\r\n /** Set by Signal Forms. Only the first message is shown. */\r\n readonly errors = input<readonly { readonly kind: string; readonly message?: string }[]>([]);\r\n /** Set by Signal Forms. Errors show only after the field is touched. */\r\n readonly touched = input(false, { transform: booleanAttribute });\r\n /** Always render a native `<select>`. */\r\n readonly native = input(false, { transform: booleanAttribute });\r\n /** Emits when the control loses focus, so forms can mark it touched. */\r\n readonly touch = output<void>();\r\n\r\n readonly labelable = true;\r\n protected readonly nativeId = injectId('select');\r\n protected readonly triggerId = this.nativeId + '-trigger';\r\n readonly id = computed(() => (this.useNative() ? this.nativeId : this.triggerId));\r\n readonly errorMessage = computed(() => {\r\n const first = this.errors()[0];\r\n return first ? (first.message ?? first.kind) : undefined;\r\n });\r\n\r\n protected readonly expanded = signal(false);\r\n /** Stays true while the panel fades out after `expanded` turns false. */\r\n protected readonly rendered = signal(false);\r\n protected readonly positions = hyDropdownPositions();\r\n protected readonly panelWidth = signal(0);\r\n protected readonly useNative = signal(true);\r\n protected readonly keyedOptions = computed(() => {\r\n const keys = new Set<string>();\r\n return this.options().map((option) => {\r\n const value = option.value;\r\n if (option.key === undefined && (typeof value === 'object' || typeof value === 'function'))\r\n throw new Error('HySelect: object values require a stable option key');\r\n const key =\r\n option.key === undefined\r\n ? `${typeof value}:${String(value)}`\r\n : `${typeof option.key}:${option.key}`;\r\n if (keys.has(key)) throw new Error('HySelect: duplicate option key ' + key);\r\n keys.add(key);\r\n return {\r\n option,\r\n key,\r\n disabled: !!(option.disabled || option.group?.disabled),\r\n context: { $implicit: option },\r\n };\r\n });\r\n });\r\n protected readonly groups = computed(() => {\r\n const groups = new Map<\r\n string,\r\n {\r\n key: string;\r\n label: string;\r\n options: {\r\n option: HySelectOption<T>;\r\n key: string;\r\n disabled: boolean;\r\n context: HySelectOptionContext<T>;\r\n }[];\r\n }\r\n >();\r\n for (const option of this.keyedOptions()) {\r\n const key = option.option.group?.key ?? '';\r\n const group = groups.get(key) ?? {\r\n key,\r\n label: option.option.group?.label ?? '',\r\n options: [],\r\n };\r\n group.options.push(option);\r\n groups.set(key, group);\r\n }\r\n return [...groups.values()];\r\n });\r\n protected readonly selectedOption = computed(() =>\r\n this.options().find((o) => o.value === this.value()),\r\n );\r\n protected readonly listValue = computed(() => {\r\n const v = this.value();\r\n return v === undefined ? [] : [v];\r\n });\r\n protected readonly showsError = computed(() =>\r\n this.field ? this.field.errorShown() : this.invalid() && this.touched(),\r\n );\r\n\r\n constructor() {\r\n afterNextRender(() => this.ready.set(true));\r\n effect(() => {\r\n this.ready();\r\n this.native();\r\n this.fidelity.tier();\r\n this.scheduleMode();\r\n });\r\n effect(() => {\r\n const open = this.expanded();\r\n untracked(() => {\r\n const panel = this.panelElement();\r\n if (open) {\r\n // Reopened while fading out: turn the exit around.\r\n if (panel && this.presence.leaving) this.presence.enter(panel);\r\n this.rendered.set(true);\r\n } else if (panel) {\r\n this.presence.leave(panel, () => this.rendered.set(false));\r\n } else {\r\n this.rendered.set(false);\r\n }\r\n });\r\n });\r\n this.field?.register({\r\n id: this.id,\r\n invalid: computed(() => this.invalid() && this.touched()),\r\n errorMessage: this.errorMessage,\r\n required: this.required,\r\n disabled: this.disabled,\r\n labelable: true,\r\n });\r\n }\r\n\r\n protected setExpanded(open: boolean): void {\r\n if (open) this.panelWidth.set(this.trigger()?.nativeElement.offsetWidth ?? 0);\r\n this.expanded.set(open);\r\n }\r\n\r\n /** Runs when the overlay attaches a fresh panel. */\r\n protected onAttach(): void {\r\n const panel = this.panelElement();\r\n if (panel) this.presence.enter(panel);\r\n }\r\n\r\n private panelElement(): HTMLElement | null {\r\n return (\r\n this.overlay()?.overlayRef?.overlayElement.querySelector<HTMLElement>('.hy-select__panel') ??\r\n null\r\n );\r\n }\r\n\r\n protected pick(values: readonly T[]): void {\r\n const next = values[values.length - 1];\r\n if (next === undefined || next === this.value()) return;\r\n this.value.set(next);\r\n this.close();\r\n }\r\n\r\n /** Closes after a click on an option, including the one already selected. */\r\n protected onPanelClick(event: MouseEvent): void {\r\n const option = (event.target as Element | null)?.closest('[role=\"option\"]');\r\n if (option && option.getAttribute('aria-disabled') !== 'true') this.close();\r\n }\r\n\r\n protected close(): void {\r\n this.expanded.set(false);\r\n this.trigger()?.nativeElement.focus();\r\n }\r\n\r\n protected scheduleMode(): void {\r\n queueMicrotask(() => {\r\n if (this.destroy.destroyed || !this.ready()) return;\r\n if (this.expanded() || this.host.contains(this.document.activeElement)) return;\r\n this.useNative.set(this.native() || this.fidelity.tier() === 'low');\r\n });\r\n }\r\n\r\n protected pickNative(event: Event): void {\r\n const key = (event.target as HTMLSelectElement).value;\r\n if (!key && !this.required()) {\r\n this.value.set(undefined);\r\n return;\r\n }\r\n const choice = this.keyedOptions().find((item) => item.key === key);\r\n if (choice && !choice.disabled) this.value.set(choice.option.value);\r\n }\r\n}\r\n","<select\r\n class=\"hy-select__native\"\r\n [hidden]=\"!useNative()\"\r\n [id]=\"nativeId\"\r\n [disabled]=\"disabled() || !useNative()\"\r\n [required]=\"required()\"\r\n [name]=\"useNative() ? name() : undefined\"\r\n [attr.aria-describedby]=\"field?.describedBy() ?? null\"\r\n [attr.aria-invalid]=\"showsError() || null\"\r\n (change)=\"pickNative($event)\"\r\n (blur)=\"touch.emit()\"\r\n>\r\n <option value=\"\" [disabled]=\"required()\" [selected]=\"!selectedOption()\">\r\n {{ placeholder() }}\r\n </option>\r\n @for (group of groups(); track group.key) {\r\n @if (group.key) {\r\n <optgroup [label]=\"group.label\">\r\n @for (item of group.options; track item.key) {\r\n <option\r\n [value]=\"item.key\"\r\n [selected]=\"item.option.value === value()\"\r\n [disabled]=\"item.disabled\"\r\n >\r\n {{ item.option.label }}\r\n </option>\r\n }\r\n </optgroup>\r\n } @else {\r\n @for (item of group.options; track item.key) {\r\n <option\r\n [value]=\"item.key\"\r\n [selected]=\"item.option.value === value()\"\r\n [disabled]=\"item.disabled\"\r\n >\r\n {{ item.option.label }}\r\n </option>\r\n }\r\n }\r\n }\r\n</select>\r\n<hy-icon [hidden]=\"!useNative()\" class=\"hy-select__chevron\" name=\"chevron-down\" />\r\n<button\r\n #trigger\r\n type=\"button\"\r\n ngCombobox\r\n #combobox=\"ngCombobox\"\r\n cdkOverlayOrigin\r\n #origin=\"cdkOverlayOrigin\"\r\n class=\"hy-select__trigger\"\r\n [hidden]=\"useNative()\"\r\n [id]=\"triggerId\"\r\n [disabled]=\"disabled() || useNative()\"\r\n [expanded]=\"expanded()\"\r\n (expandedChange)=\"setExpanded($event)\"\r\n [attr.aria-labelledby]=\"field ? field.labelId + ' ' + triggerId : null\"\r\n [attr.aria-describedby]=\"field?.describedBy() ?? null\"\r\n [attr.aria-invalid]=\"showsError() || null\"\r\n [attr.aria-required]=\"required() || null\"\r\n (blur)=\"touch.emit()\"\r\n>\r\n <span class=\"hy-select__value\" [class.hy-select__placeholder]=\"!selectedOption()\">{{\r\n selectedOption()?.label ?? placeholder()\r\n }}</span>\r\n <hy-icon class=\"hy-select__chevron\" name=\"chevron-down\" />\r\n</button>\r\n<ng-template ngComboboxPopup [combobox]=\"combobox\">\r\n <ng-template\r\n cdkConnectedOverlay\r\n [cdkConnectedOverlayOrigin]=\"origin\"\r\n [cdkConnectedOverlayOpen]=\"rendered() && !useNative()\"\r\n [cdkConnectedOverlayPositions]=\"positions\"\r\n [cdkConnectedOverlayMinWidth]=\"panelWidth()\"\r\n cdkConnectedOverlayPanelClass=\"hy-select-overlay\"\r\n cdkConnectedOverlayTransformOriginOn=\".hy-select__panel\"\r\n (attach)=\"onAttach()\"\r\n (overlayOutsideClick)=\"expanded.set(false)\"\r\n >\r\n <!-- Focus remains on the combobox trigger while Aria manages the active option. -->\r\n <!-- eslint-disable-next-line @angular-eslint/template/interactive-supports-focus -->\r\n <div\r\n ngComboboxWidget\r\n ngListbox\r\n #listbox=\"ngListbox\"\r\n class=\"hy-select__panel hy-glass\"\r\n data-material=\"frosted\"\r\n focusMode=\"activedescendant\"\r\n selectionMode=\"explicit\"\r\n [activeDescendant]=\"listbox.activeDescendant()\"\r\n [value]=\"listValue()\"\r\n (valueChange)=\"pick($event)\"\r\n (click)=\"onPanelClick($event)\"\r\n (keydown.enter)=\"close()\"\r\n (keydown.space)=\"close()\"\r\n >\r\n @for (group of groups(); track group.key) {\r\n <div role=\"group\" [attr.aria-label]=\"group.label || null\">\r\n @if (group.label) {\r\n <div class=\"hy-select__group-label\">{{ group.label }}</div>\r\n }\r\n @for (item of group.options; track item.key) {\r\n <div\r\n ngOption\r\n class=\"hy-select__option\"\r\n [value]=\"item.option.value\"\r\n [label]=\"item.option.label\"\r\n [disabled]=\"item.disabled\"\r\n >\r\n @if (optionTemplate(); as template) {\r\n <ng-container\r\n [ngTemplateOutlet]=\"template\"\r\n [ngTemplateOutletContext]=\"item.context\"\r\n />\r\n } @else {\r\n <span>{{ item.option.label }}</span>\r\n }\r\n <hy-icon class=\"hy-select__check\" name=\"check\" />\r\n </div>\r\n }\r\n </div>\r\n }\r\n </div>\r\n </ng-template>\r\n</ng-template>\r\n"],"mappings":"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"}
@@ -0,0 +1,241 @@
1
+ import * as i0 from "@angular/core";
2
+ import { ChangeDetectionStrategy, Component, booleanAttribute, input, model } from "@angular/core";
3
+ import { HyIcon } from "@hyalo/angular/icon";
4
+ var HySidebar = class HySidebar {
5
+ collapsed = model(false, ...ngDevMode ? [{ debugName: "collapsed" }] : /* istanbul ignore next */ []);
6
+ toggle = (value) => !value;
7
+ label = input("Main navigation", ...ngDevMode ? [{ debugName: "label" }] : /* istanbul ignore next */ []);
8
+ collapseLabel = input("Collapse navigation", ...ngDevMode ? [{ debugName: "collapseLabel" }] : /* istanbul ignore next */ []);
9
+ expandLabel = input("Expand navigation", ...ngDevMode ? [{ debugName: "expandLabel" }] : /* istanbul ignore next */ []);
10
+ static ɵfac = i0.ɵɵngDeclareFactory({
11
+ minVersion: "12.0.0",
12
+ version: "22.2.3",
13
+ ngImport: i0,
14
+ type: HySidebar,
15
+ deps: [],
16
+ target: i0.ɵɵFactoryTarget.Component
17
+ });
18
+ static ɵcmp = i0.ɵɵngDeclareComponent({
19
+ minVersion: "17.1.0",
20
+ version: "22.2.3",
21
+ type: HySidebar,
22
+ isStandalone: true,
23
+ selector: "hy-sidebar",
24
+ inputs: {
25
+ collapsed: {
26
+ classPropertyName: "collapsed",
27
+ publicName: "collapsed",
28
+ isSignal: true,
29
+ isRequired: false,
30
+ transformFunction: null
31
+ },
32
+ label: {
33
+ classPropertyName: "label",
34
+ publicName: "label",
35
+ isSignal: true,
36
+ isRequired: false,
37
+ transformFunction: null
38
+ },
39
+ collapseLabel: {
40
+ classPropertyName: "collapseLabel",
41
+ publicName: "collapseLabel",
42
+ isSignal: true,
43
+ isRequired: false,
44
+ transformFunction: null
45
+ },
46
+ expandLabel: {
47
+ classPropertyName: "expandLabel",
48
+ publicName: "expandLabel",
49
+ isSignal: true,
50
+ isRequired: false,
51
+ transformFunction: null
52
+ }
53
+ },
54
+ outputs: { collapsed: "collapsedChange" },
55
+ host: { properties: {
56
+ "attr.data-collapsed": "collapsed()",
57
+ "style.--hy-sidebar-label-display": "collapsed()?\"none\":null",
58
+ "style.--hy-sidebar-item-justify": "collapsed()?\"center\":null"
59
+ } },
60
+ ngImport: i0,
61
+ template: "<header>\n <div class=\"brand\"><ng-content select=\"[hySidebarBrand]\" /></div>\n <button\n type=\"button\"\n [attr.aria-label]=\"collapsed() ? expandLabel() : collapseLabel()\"\n [attr.aria-expanded]=\"!collapsed()\"\n (click)=\"collapsed.update(toggle)\"\n >\n <svg\n viewBox=\"0 0 24 24\"\n width=\"20\"\n height=\"20\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"1.75\"\n aria-hidden=\"true\"\n >\n <rect x=\"3\" y=\"4\" width=\"18\" height=\"16\" rx=\"3\" />\n <path d=\"M9 4v16\" />\n </svg>\n </button>\n</header>\n<nav [attr.aria-label]=\"label()\"><ng-content /></nav>\n<footer><ng-content select=\"[hySidebarFooter]\" /></footer>\n",
62
+ styles: [":host{display:flex;flex-direction:column;flex:none;gap:1.5rem;inline-size:var(--hy-sidebar-width, 16rem);max-inline-size:100%;min-inline-size:0;padding:.75rem;border:1px solid var(--hy-line);border-radius:var(--hy-radius-m);background:var(--hy-surface-2);box-sizing:border-box}:host([data-collapsed=\"true\"]){inline-size:4.5rem}header{display:flex;align-items:center;justify-content:space-between;gap:.5rem;min-block-size:44px}.brand{display:var(--hy-sidebar-label-display, block);min-inline-size:0;padding-inline-start:.375rem}button{display:grid;place-items:center;flex:none;inline-size:44px;block-size:44px;padding:0;background:transparent;color:var(--hy-ink-2);border:1px solid transparent;border-radius:var(--hy-radius-s);cursor:pointer;transition:background-color .12s ease,color .12s ease}button svg{transition:transform var(--hy-dur-quick) var(--hy-ease-out)}:host([data-collapsed=\"true\"]) button svg{transform:rotateY(180deg)}:host-context([dir=\"rtl\"]) button svg{scale:-1 1}@media(hover:hover)and (pointer:fine){button:hover{background:var(--hy-surface-3);color:var(--hy-ink)}}button:active{background:var(--hy-surface-4)}nav{display:grid;align-content:start;gap:.375rem}footer{margin-block-start:auto;display:var(--hy-sidebar-label-display, block);padding-block-start:1rem;border-block-start:1px solid var(--hy-line)}footer:empty{display:none}button:focus-visible{outline:2px solid var(--hy-primary);outline-offset:2px}@media(prefers-reduced-motion:reduce){button svg{transition:none}}:host-context([data-hy-motion=\"reduced\"]) button svg{transition:none}\n"],
63
+ changeDetection: i0.ChangeDetectionStrategy.OnPush
64
+ });
65
+ };
66
+ i0.ɵɵngDeclareClassMetadata({
67
+ minVersion: "12.0.0",
68
+ version: "22.2.3",
69
+ ngImport: i0,
70
+ type: HySidebar,
71
+ decorators: [{
72
+ type: Component,
73
+ args: [{
74
+ selector: "hy-sidebar",
75
+ changeDetection: ChangeDetectionStrategy.OnPush,
76
+ host: {
77
+ "[attr.data-collapsed]": "collapsed()",
78
+ "[style.--hy-sidebar-label-display]": "collapsed()?\"none\":null",
79
+ "[style.--hy-sidebar-item-justify]": "collapsed()?\"center\":null"
80
+ },
81
+ template: "<header>\n <div class=\"brand\"><ng-content select=\"[hySidebarBrand]\" /></div>\n <button\n type=\"button\"\n [attr.aria-label]=\"collapsed() ? expandLabel() : collapseLabel()\"\n [attr.aria-expanded]=\"!collapsed()\"\n (click)=\"collapsed.update(toggle)\"\n >\n <svg\n viewBox=\"0 0 24 24\"\n width=\"20\"\n height=\"20\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"1.75\"\n aria-hidden=\"true\"\n >\n <rect x=\"3\" y=\"4\" width=\"18\" height=\"16\" rx=\"3\" />\n <path d=\"M9 4v16\" />\n </svg>\n </button>\n</header>\n<nav [attr.aria-label]=\"label()\"><ng-content /></nav>\n<footer><ng-content select=\"[hySidebarFooter]\" /></footer>\n",
82
+ styles: [":host{display:flex;flex-direction:column;flex:none;gap:1.5rem;inline-size:var(--hy-sidebar-width, 16rem);max-inline-size:100%;min-inline-size:0;padding:.75rem;border:1px solid var(--hy-line);border-radius:var(--hy-radius-m);background:var(--hy-surface-2);box-sizing:border-box}:host([data-collapsed=\"true\"]){inline-size:4.5rem}header{display:flex;align-items:center;justify-content:space-between;gap:.5rem;min-block-size:44px}.brand{display:var(--hy-sidebar-label-display, block);min-inline-size:0;padding-inline-start:.375rem}button{display:grid;place-items:center;flex:none;inline-size:44px;block-size:44px;padding:0;background:transparent;color:var(--hy-ink-2);border:1px solid transparent;border-radius:var(--hy-radius-s);cursor:pointer;transition:background-color .12s ease,color .12s ease}button svg{transition:transform var(--hy-dur-quick) var(--hy-ease-out)}:host([data-collapsed=\"true\"]) button svg{transform:rotateY(180deg)}:host-context([dir=\"rtl\"]) button svg{scale:-1 1}@media(hover:hover)and (pointer:fine){button:hover{background:var(--hy-surface-3);color:var(--hy-ink)}}button:active{background:var(--hy-surface-4)}nav{display:grid;align-content:start;gap:.375rem}footer{margin-block-start:auto;display:var(--hy-sidebar-label-display, block);padding-block-start:1rem;border-block-start:1px solid var(--hy-line)}footer:empty{display:none}button:focus-visible{outline:2px solid var(--hy-primary);outline-offset:2px}@media(prefers-reduced-motion:reduce){button svg{transition:none}}:host-context([data-hy-motion=\"reduced\"]) button svg{transition:none}\n"]
83
+ }]
84
+ }],
85
+ propDecorators: {
86
+ collapsed: [{
87
+ type: i0.Input,
88
+ args: [{
89
+ isSignal: true,
90
+ alias: "collapsed",
91
+ required: false
92
+ }]
93
+ }, {
94
+ type: i0.Output,
95
+ args: ["collapsedChange"]
96
+ }],
97
+ label: [{
98
+ type: i0.Input,
99
+ args: [{
100
+ isSignal: true,
101
+ alias: "label",
102
+ required: false
103
+ }]
104
+ }],
105
+ collapseLabel: [{
106
+ type: i0.Input,
107
+ args: [{
108
+ isSignal: true,
109
+ alias: "collapseLabel",
110
+ required: false
111
+ }]
112
+ }],
113
+ expandLabel: [{
114
+ type: i0.Input,
115
+ args: [{
116
+ isSignal: true,
117
+ alias: "expandLabel",
118
+ required: false
119
+ }]
120
+ }]
121
+ }
122
+ });
123
+ var HySidebarItem = class HySidebarItem {
124
+ label = input.required(...ngDevMode ? [{ debugName: "label" }] : /* istanbul ignore next */ []);
125
+ icon = input.required(...ngDevMode ? [{ debugName: "icon" }] : /* istanbul ignore next */ []);
126
+ active = input(false, {
127
+ ...ngDevMode ? { debugName: "active" } : /* istanbul ignore next */ {},
128
+ transform: booleanAttribute
129
+ });
130
+ static ɵfac = i0.ɵɵngDeclareFactory({
131
+ minVersion: "12.0.0",
132
+ version: "22.2.3",
133
+ ngImport: i0,
134
+ type: HySidebarItem,
135
+ deps: [],
136
+ target: i0.ɵɵFactoryTarget.Component
137
+ });
138
+ static ɵcmp = i0.ɵɵngDeclareComponent({
139
+ minVersion: "17.1.0",
140
+ version: "22.2.3",
141
+ type: HySidebarItem,
142
+ isStandalone: true,
143
+ selector: "a[hySidebarItem]",
144
+ inputs: {
145
+ label: {
146
+ classPropertyName: "label",
147
+ publicName: "label",
148
+ isSignal: true,
149
+ isRequired: true,
150
+ transformFunction: null
151
+ },
152
+ icon: {
153
+ classPropertyName: "icon",
154
+ publicName: "icon",
155
+ isSignal: true,
156
+ isRequired: true,
157
+ transformFunction: null
158
+ },
159
+ active: {
160
+ classPropertyName: "active",
161
+ publicName: "active",
162
+ isSignal: true,
163
+ isRequired: false,
164
+ transformFunction: null
165
+ }
166
+ },
167
+ host: { properties: {
168
+ "attr.aria-label": "label()",
169
+ "attr.title": "label()",
170
+ "attr.aria-current": "active()?\"page\":null"
171
+ } },
172
+ ngImport: i0,
173
+ template: "<hy-icon [name]=\"icon()\" /><span class=\"label\">{{label()}}</span><ng-content />",
174
+ isInline: true,
175
+ styles: [":host{display:flex;align-items:center;justify-content:var(--hy-sidebar-item-justify, start);gap:.75rem;min-block-size:44px;min-inline-size:0;padding:.625rem .75rem;border:1px solid transparent;border-radius:var(--hy-radius-s);color:var(--hy-ink-2);text-decoration:none;font-size:.875rem;font-weight:500;line-height:1.4;box-sizing:border-box;transition:background-color .12s ease,color .12s ease}.label{display:var(--hy-sidebar-label-display, inline);min-inline-size:0;overflow-wrap:anywhere}@media(hover:hover)and (pointer:fine){:host(:hover){background:var(--hy-surface-3);color:var(--hy-ink)}}:host(:active){background:var(--hy-surface-4)}:host([aria-current=\"page\"]){background:var(--hy-primary-wash);color:var(--hy-primary);font-weight:600}:host(:focus-visible){outline:2px solid var(--hy-primary);outline-offset:2px}hy-icon{flex:none;inline-size:1.125rem;block-size:1.125rem}\n"],
176
+ dependencies: [{
177
+ kind: "component",
178
+ type: HyIcon,
179
+ selector: "hy-icon",
180
+ inputs: [
181
+ "name",
182
+ "icon",
183
+ "label",
184
+ "size",
185
+ "strokeWidth"
186
+ ]
187
+ }],
188
+ changeDetection: i0.ChangeDetectionStrategy.OnPush
189
+ });
190
+ };
191
+ i0.ɵɵngDeclareClassMetadata({
192
+ minVersion: "12.0.0",
193
+ version: "22.2.3",
194
+ ngImport: i0,
195
+ type: HySidebarItem,
196
+ decorators: [{
197
+ type: Component,
198
+ args: [{
199
+ selector: "a[hySidebarItem]",
200
+ imports: [HyIcon],
201
+ changeDetection: ChangeDetectionStrategy.OnPush,
202
+ template: "<hy-icon [name]=\"icon()\" /><span class=\"label\">{{label()}}</span><ng-content />",
203
+ host: {
204
+ "[attr.aria-label]": "label()",
205
+ "[attr.title]": "label()",
206
+ "[attr.aria-current]": "active()?\"page\":null"
207
+ },
208
+ styles: [":host{display:flex;align-items:center;justify-content:var(--hy-sidebar-item-justify, start);gap:.75rem;min-block-size:44px;min-inline-size:0;padding:.625rem .75rem;border:1px solid transparent;border-radius:var(--hy-radius-s);color:var(--hy-ink-2);text-decoration:none;font-size:.875rem;font-weight:500;line-height:1.4;box-sizing:border-box;transition:background-color .12s ease,color .12s ease}.label{display:var(--hy-sidebar-label-display, inline);min-inline-size:0;overflow-wrap:anywhere}@media(hover:hover)and (pointer:fine){:host(:hover){background:var(--hy-surface-3);color:var(--hy-ink)}}:host(:active){background:var(--hy-surface-4)}:host([aria-current=\"page\"]){background:var(--hy-primary-wash);color:var(--hy-primary);font-weight:600}:host(:focus-visible){outline:2px solid var(--hy-primary);outline-offset:2px}hy-icon{flex:none;inline-size:1.125rem;block-size:1.125rem}\n"]
209
+ }]
210
+ }],
211
+ propDecorators: {
212
+ label: [{
213
+ type: i0.Input,
214
+ args: [{
215
+ isSignal: true,
216
+ alias: "label",
217
+ required: true
218
+ }]
219
+ }],
220
+ icon: [{
221
+ type: i0.Input,
222
+ args: [{
223
+ isSignal: true,
224
+ alias: "icon",
225
+ required: true
226
+ }]
227
+ }],
228
+ active: [{
229
+ type: i0.Input,
230
+ args: [{
231
+ isSignal: true,
232
+ alias: "active",
233
+ required: false
234
+ }]
235
+ }]
236
+ }
237
+ });
238
+ const HY_SIDEBAR = [HySidebar, HySidebarItem];
239
+ export { HY_SIDEBAR, HySidebar, HySidebarItem };
240
+
241
+ //# sourceMappingURL=hyalo-angular-sidebar.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"hyalo-angular-sidebar.mjs","names":[],"sources":["../../../projects/hyalo/sidebar/sidebar.ts","../../../projects/hyalo/sidebar/sidebar.html"],"sourcesContent":["import { ChangeDetectionStrategy, Component, booleanAttribute, input, model } from '@angular/core';\nimport { HyIcon } from '@hyalo/angular/icon';\n@Component({\n selector: 'hy-sidebar',\n changeDetection: ChangeDetectionStrategy.OnPush,\n templateUrl: './sidebar.html',\n styleUrl: './sidebar.css',\n host: {\n '[attr.data-collapsed]': 'collapsed()',\n '[style.--hy-sidebar-label-display]': 'collapsed()?\"none\":null',\n '[style.--hy-sidebar-item-justify]': 'collapsed()?\"center\":null',\n },\n})\nexport class HySidebar {\n readonly collapsed = model(false);\n protected readonly toggle = (value: boolean): boolean => !value;\n readonly label = input('Main navigation');\n readonly collapseLabel = input('Collapse navigation');\n readonly expandLabel = input('Expand navigation');\n}\n@Component({\n // Native elements preserve link, list, key, and button semantics.\n // eslint-disable-next-line @angular-eslint/component-selector\n selector: 'a[hySidebarItem]',\n imports: [HyIcon],\n changeDetection: ChangeDetectionStrategy.OnPush,\n template: '<hy-icon [name]=\"icon()\" /><span class=\"label\">{{label()}}</span><ng-content />',\n host: {\n '[attr.aria-label]': 'label()',\n '[attr.title]': 'label()',\n '[attr.aria-current]': 'active()?\"page\":null',\n },\n styleUrl: './sidebar-item.css',\n})\nexport class HySidebarItem {\n readonly label = input.required<string>();\n readonly icon = input.required<string>();\n readonly active = input(false, { transform: booleanAttribute });\n}\nexport const HY_SIDEBAR = [HySidebar, HySidebarItem] as const;\n","<header>\n <div class=\"brand\"><ng-content select=\"[hySidebarBrand]\" /></div>\n <button\n type=\"button\"\n [attr.aria-label]=\"collapsed() ? expandLabel() : collapseLabel()\"\n [attr.aria-expanded]=\"!collapsed()\"\n (click)=\"collapsed.update(toggle)\"\n >\n <svg\n viewBox=\"0 0 24 24\"\n width=\"20\"\n height=\"20\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"1.75\"\n aria-hidden=\"true\"\n >\n <rect x=\"3\" y=\"4\" width=\"18\" height=\"16\" rx=\"3\" />\n <path d=\"M9 4v16\" />\n </svg>\n </button>\n</header>\n<nav [attr.aria-label]=\"label()\"><ng-content /></nav>\n<footer><ng-content select=\"[hySidebarFooter]\" /></footer>\n"],"mappings":"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"}