@hyalo/angular 0.0.0-stage → 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 (229) hide show
  1. package/CHANGELOG.md +95 -0
  2. package/LICENSE +21 -0
  3. package/README.md +45 -2
  4. package/fesm2022/hyalo-angular-accordion.mjs +230 -0
  5. package/fesm2022/hyalo-angular-accordion.mjs.map +1 -0
  6. package/fesm2022/hyalo-angular-alert.mjs +171 -0
  7. package/fesm2022/hyalo-angular-alert.mjs.map +1 -0
  8. package/fesm2022/hyalo-angular-aspect-ratio.mjs +64 -0
  9. package/fesm2022/hyalo-angular-aspect-ratio.mjs.map +1 -0
  10. package/fesm2022/hyalo-angular-avatar.mjs +169 -0
  11. package/fesm2022/hyalo-angular-avatar.mjs.map +1 -0
  12. package/fesm2022/hyalo-angular-badge.mjs +268 -0
  13. package/fesm2022/hyalo-angular-badge.mjs.map +1 -0
  14. package/fesm2022/hyalo-angular-bento.mjs +132 -0
  15. package/fesm2022/hyalo-angular-bento.mjs.map +1 -0
  16. package/fesm2022/hyalo-angular-blocks.mjs +985 -0
  17. package/fesm2022/hyalo-angular-blocks.mjs.map +1 -0
  18. package/fesm2022/hyalo-angular-border-beam.mjs +73 -0
  19. package/fesm2022/hyalo-angular-border-beam.mjs.map +1 -0
  20. package/fesm2022/hyalo-angular-breadcrumb.mjs +77 -0
  21. package/fesm2022/hyalo-angular-breadcrumb.mjs.map +1 -0
  22. package/fesm2022/hyalo-angular-button-group.mjs +90 -0
  23. package/fesm2022/hyalo-angular-button-group.mjs.map +1 -0
  24. package/fesm2022/hyalo-angular-button.mjs +204 -0
  25. package/fesm2022/hyalo-angular-button.mjs.map +1 -0
  26. package/fesm2022/hyalo-angular-card.mjs +221 -0
  27. package/fesm2022/hyalo-angular-card.mjs.map +1 -0
  28. package/fesm2022/hyalo-angular-carousel.mjs +709 -0
  29. package/fesm2022/hyalo-angular-carousel.mjs.map +1 -0
  30. package/fesm2022/hyalo-angular-chapter-nav.mjs +336 -0
  31. package/fesm2022/hyalo-angular-chapter-nav.mjs.map +1 -0
  32. package/fesm2022/hyalo-angular-chart-engine-DSJop6He.mjs +5 -0
  33. package/fesm2022/hyalo-angular-chart-engine-DSJop6He.mjs.map +1 -0
  34. package/fesm2022/hyalo-angular-chart.mjs +391 -0
  35. package/fesm2022/hyalo-angular-chart.mjs.map +1 -0
  36. package/fesm2022/hyalo-angular-choice.mjs +789 -0
  37. package/fesm2022/hyalo-angular-choice.mjs.map +1 -0
  38. package/fesm2022/hyalo-angular-code-block-highlight-B20d5C76.mjs +40 -0
  39. package/fesm2022/hyalo-angular-code-block-highlight-B20d5C76.mjs.map +1 -0
  40. package/fesm2022/hyalo-angular-code-block.mjs +161 -0
  41. package/fesm2022/hyalo-angular-code-block.mjs.map +1 -0
  42. package/fesm2022/hyalo-angular-command.mjs +193 -0
  43. package/fesm2022/hyalo-angular-command.mjs.map +1 -0
  44. package/fesm2022/hyalo-angular-copy.mjs +138 -0
  45. package/fesm2022/hyalo-angular-copy.mjs.map +1 -0
  46. package/fesm2022/hyalo-angular-core.mjs +424 -0
  47. package/fesm2022/hyalo-angular-core.mjs.map +1 -0
  48. package/fesm2022/hyalo-angular-description-list.mjs +57 -0
  49. package/fesm2022/hyalo-angular-description-list.mjs.map +1 -0
  50. package/fesm2022/hyalo-angular-dialog.mjs +600 -0
  51. package/fesm2022/hyalo-angular-dialog.mjs.map +1 -0
  52. package/fesm2022/hyalo-angular-divider.mjs +66 -0
  53. package/fesm2022/hyalo-angular-divider.mjs.map +1 -0
  54. package/fesm2022/hyalo-angular-empty-state.mjs +123 -0
  55. package/fesm2022/hyalo-angular-empty-state.mjs.map +1 -0
  56. package/fesm2022/hyalo-angular-field.mjs +344 -0
  57. package/fesm2022/hyalo-angular-field.mjs.map +1 -0
  58. package/fesm2022/hyalo-angular-filter.mjs +309 -0
  59. package/fesm2022/hyalo-angular-filter.mjs.map +1 -0
  60. package/fesm2022/hyalo-angular-hotspot.mjs +225 -0
  61. package/fesm2022/hyalo-angular-hotspot.mjs.map +1 -0
  62. package/fesm2022/hyalo-angular-hover-card.mjs +233 -0
  63. package/fesm2022/hyalo-angular-hover-card.mjs.map +1 -0
  64. package/fesm2022/hyalo-angular-icon.mjs +385 -0
  65. package/fesm2022/hyalo-angular-icon.mjs.map +1 -0
  66. package/fesm2022/hyalo-angular-image-compare.mjs +168 -0
  67. package/fesm2022/hyalo-angular-image-compare.mjs.map +1 -0
  68. package/fesm2022/hyalo-angular-interaction.mjs +446 -0
  69. package/fesm2022/hyalo-angular-interaction.mjs.map +1 -0
  70. package/fesm2022/hyalo-angular-kbd.mjs +41 -0
  71. package/fesm2022/hyalo-angular-kbd.mjs.map +1 -0
  72. package/fesm2022/hyalo-angular-lightbox.mjs +228 -0
  73. package/fesm2022/hyalo-angular-lightbox.mjs.map +1 -0
  74. package/fesm2022/hyalo-angular-link.mjs +42 -0
  75. package/fesm2022/hyalo-angular-link.mjs.map +1 -0
  76. package/fesm2022/hyalo-angular-list.mjs +131 -0
  77. package/fesm2022/hyalo-angular-list.mjs.map +1 -0
  78. package/fesm2022/hyalo-angular-marquee.mjs +197 -0
  79. package/fesm2022/hyalo-angular-marquee.mjs.map +1 -0
  80. package/fesm2022/hyalo-angular-menu.mjs +423 -0
  81. package/fesm2022/hyalo-angular-menu.mjs.map +1 -0
  82. package/fesm2022/hyalo-angular-mesh.mjs +126 -0
  83. package/fesm2022/hyalo-angular-mesh.mjs.map +1 -0
  84. package/fesm2022/hyalo-angular-motion.mjs +620 -0
  85. package/fesm2022/hyalo-angular-motion.mjs.map +1 -0
  86. package/fesm2022/hyalo-angular-navbar.mjs +343 -0
  87. package/fesm2022/hyalo-angular-navbar.mjs.map +1 -0
  88. package/fesm2022/hyalo-angular-navigation-menu.mjs +222 -0
  89. package/fesm2022/hyalo-angular-navigation-menu.mjs.map +1 -0
  90. package/fesm2022/hyalo-angular-number-ticker.mjs +174 -0
  91. package/fesm2022/hyalo-angular-number-ticker.mjs.map +1 -0
  92. package/fesm2022/hyalo-angular-overlay.mjs +163 -0
  93. package/fesm2022/hyalo-angular-overlay.mjs.map +1 -0
  94. package/fesm2022/hyalo-angular-pagination.mjs +187 -0
  95. package/fesm2022/hyalo-angular-pagination.mjs.map +1 -0
  96. package/fesm2022/hyalo-angular-popover-overlay-kit-6wPwnxln.mjs +3 -0
  97. package/fesm2022/hyalo-angular-popover.mjs +516 -0
  98. package/fesm2022/hyalo-angular-popover.mjs.map +1 -0
  99. package/fesm2022/hyalo-angular-progress.mjs +209 -0
  100. package/fesm2022/hyalo-angular-progress.mjs.map +1 -0
  101. package/fesm2022/hyalo-angular-progressive-blur.mjs +73 -0
  102. package/fesm2022/hyalo-angular-progressive-blur.mjs.map +1 -0
  103. package/fesm2022/hyalo-angular-refraction-renderer-5ZA-kfsA.mjs +186 -0
  104. package/fesm2022/hyalo-angular-refraction-renderer-5ZA-kfsA.mjs.map +1 -0
  105. package/fesm2022/hyalo-angular-refraction.mjs +178 -0
  106. package/fesm2022/hyalo-angular-refraction.mjs.map +1 -0
  107. package/fesm2022/hyalo-angular-scroll-area.mjs +93 -0
  108. package/fesm2022/hyalo-angular-scroll-area.mjs.map +1 -0
  109. package/fesm2022/hyalo-angular-scroll-to-top.mjs +127 -0
  110. package/fesm2022/hyalo-angular-scroll-to-top.mjs.map +1 -0
  111. package/fesm2022/hyalo-angular-segmented.mjs +223 -0
  112. package/fesm2022/hyalo-angular-segmented.mjs.map +1 -0
  113. package/fesm2022/hyalo-angular-select.mjs +561 -0
  114. package/fesm2022/hyalo-angular-select.mjs.map +1 -0
  115. package/fesm2022/hyalo-angular-sidebar.mjs +241 -0
  116. package/fesm2022/hyalo-angular-sidebar.mjs.map +1 -0
  117. package/fesm2022/hyalo-angular-skeleton.mjs +131 -0
  118. package/fesm2022/hyalo-angular-skeleton.mjs.map +1 -0
  119. package/fesm2022/hyalo-angular-sparkline.mjs +110 -0
  120. package/fesm2022/hyalo-angular-sparkline.mjs.map +1 -0
  121. package/fesm2022/hyalo-angular-split-text.mjs +126 -0
  122. package/fesm2022/hyalo-angular-split-text.mjs.map +1 -0
  123. package/fesm2022/hyalo-angular-stat.mjs +193 -0
  124. package/fesm2022/hyalo-angular-stat.mjs.map +1 -0
  125. package/fesm2022/hyalo-angular-stepper.mjs +254 -0
  126. package/fesm2022/hyalo-angular-stepper.mjs.map +1 -0
  127. package/fesm2022/hyalo-angular-table.mjs +335 -0
  128. package/fesm2022/hyalo-angular-table.mjs.map +1 -0
  129. package/fesm2022/hyalo-angular-tabs.mjs +324 -0
  130. package/fesm2022/hyalo-angular-tabs.mjs.map +1 -0
  131. package/fesm2022/hyalo-angular-theme.mjs +94 -0
  132. package/fesm2022/hyalo-angular-theme.mjs.map +1 -0
  133. package/fesm2022/hyalo-angular-timeline.mjs +157 -0
  134. package/fesm2022/hyalo-angular-timeline.mjs.map +1 -0
  135. package/fesm2022/hyalo-angular-toast.mjs +323 -0
  136. package/fesm2022/hyalo-angular-toast.mjs.map +1 -0
  137. package/fesm2022/hyalo-angular.mjs +2 -0
  138. package/package.json +329 -3
  139. package/styles/hyalo-core.css +25 -0
  140. package/styles/hyalo.css +17 -0
  141. package/styles/overlays/dialog.css +9 -0
  142. package/styles/overlays/popover.css +9 -0
  143. package/styles/overlays/select.css +9 -0
  144. package/styles/overlays/toast.css +8 -0
  145. package/styles/palettes/aurora.css +47 -0
  146. package/styles/palettes/ember.css +47 -0
  147. package/styles/palettes/graphite.css +47 -0
  148. package/styles/palettes/ocean.css +47 -0
  149. package/styles/palettes/orchid.css +47 -0
  150. package/styles/palettes/rose.css +47 -0
  151. package/styles/parts/card.css +49 -0
  152. package/styles/parts/dialog.css +116 -0
  153. package/styles/parts/drawer.css +124 -0
  154. package/styles/parts/field.css +44 -0
  155. package/styles/parts/glass.css +139 -0
  156. package/styles/parts/motion.css +101 -0
  157. package/styles/parts/navbar.css +55 -0
  158. package/styles/parts/popover.css +27 -0
  159. package/styles/parts/presence.css +55 -0
  160. package/styles/parts/reset.css +42 -0
  161. package/styles/parts/select.css +46 -0
  162. package/styles/parts/themes.css +105 -0
  163. package/styles/parts/toast.css +128 -0
  164. package/styles/parts/tokens.css +151 -0
  165. package/styles/parts/typography.css +81 -0
  166. package/types/hyalo-angular-accordion.d.ts +74 -0
  167. package/types/hyalo-angular-alert.d.ts +47 -0
  168. package/types/hyalo-angular-aspect-ratio.d.ts +13 -0
  169. package/types/hyalo-angular-avatar.d.ts +39 -0
  170. package/types/hyalo-angular-badge.d.ts +82 -0
  171. package/types/hyalo-angular-bento.d.ts +25 -0
  172. package/types/hyalo-angular-blocks.d.ts +272 -0
  173. package/types/hyalo-angular-border-beam.d.ts +15 -0
  174. package/types/hyalo-angular-breadcrumb.d.ts +22 -0
  175. package/types/hyalo-angular-button-group.d.ts +19 -0
  176. package/types/hyalo-angular-button.d.ts +89 -0
  177. package/types/hyalo-angular-card.d.ts +61 -0
  178. package/types/hyalo-angular-carousel.d.ts +147 -0
  179. package/types/hyalo-angular-chapter-nav.d.ts +79 -0
  180. package/types/hyalo-angular-chart.d.ts +90 -0
  181. package/types/hyalo-angular-choice.d.ts +259 -0
  182. package/types/hyalo-angular-code-block.d.ts +46 -0
  183. package/types/hyalo-angular-command.d.ts +41 -0
  184. package/types/hyalo-angular-copy.d.ts +39 -0
  185. package/types/hyalo-angular-core.d.ts +210 -0
  186. package/types/hyalo-angular-description-list.d.ts +16 -0
  187. package/types/hyalo-angular-dialog.d.ts +171 -0
  188. package/types/hyalo-angular-divider.d.ts +12 -0
  189. package/types/hyalo-angular-empty-state.d.ts +30 -0
  190. package/types/hyalo-angular-field.d.ts +141 -0
  191. package/types/hyalo-angular-filter.d.ts +122 -0
  192. package/types/hyalo-angular-hotspot.d.ts +70 -0
  193. package/types/hyalo-angular-hover-card.d.ts +47 -0
  194. package/types/hyalo-angular-icon.d.ts +122 -0
  195. package/types/hyalo-angular-image-compare.d.ts +55 -0
  196. package/types/hyalo-angular-interaction.d.ts +131 -0
  197. package/types/hyalo-angular-kbd.d.ts +5 -0
  198. package/types/hyalo-angular-lightbox.d.ts +67 -0
  199. package/types/hyalo-angular-link.d.ts +5 -0
  200. package/types/hyalo-angular-list.d.ts +30 -0
  201. package/types/hyalo-angular-marquee.d.ts +48 -0
  202. package/types/hyalo-angular-menu.d.ts +105 -0
  203. package/types/hyalo-angular-mesh.d.ts +36 -0
  204. package/types/hyalo-angular-motion.d.ts +218 -0
  205. package/types/hyalo-angular-navbar.d.ts +110 -0
  206. package/types/hyalo-angular-navigation-menu.d.ts +47 -0
  207. package/types/hyalo-angular-number-ticker.d.ts +52 -0
  208. package/types/hyalo-angular-overlay.d.ts +40 -0
  209. package/types/hyalo-angular-pagination.d.ts +59 -0
  210. package/types/hyalo-angular-popover.d.ts +152 -0
  211. package/types/hyalo-angular-progress.d.ts +46 -0
  212. package/types/hyalo-angular-progressive-blur.d.ts +14 -0
  213. package/types/hyalo-angular-refraction.d.ts +46 -0
  214. package/types/hyalo-angular-scroll-area.d.ts +18 -0
  215. package/types/hyalo-angular-scroll-to-top.d.ts +31 -0
  216. package/types/hyalo-angular-segmented.d.ts +79 -0
  217. package/types/hyalo-angular-select.d.ts +176 -0
  218. package/types/hyalo-angular-sidebar.d.ts +57 -0
  219. package/types/hyalo-angular-skeleton.d.ts +34 -0
  220. package/types/hyalo-angular-sparkline.d.ts +19 -0
  221. package/types/hyalo-angular-split-text.d.ts +24 -0
  222. package/types/hyalo-angular-stat.d.ts +56 -0
  223. package/types/hyalo-angular-stepper.d.ts +63 -0
  224. package/types/hyalo-angular-table.d.ts +125 -0
  225. package/types/hyalo-angular-tabs.d.ts +102 -0
  226. package/types/hyalo-angular-theme.d.ts +46 -0
  227. package/types/hyalo-angular-timeline.d.ts +36 -0
  228. package/types/hyalo-angular-toast.d.ts +79 -0
  229. package/types/hyalo-angular.d.ts +2 -0
@@ -0,0 +1 @@
1
+ {"version":3,"file":"hyalo-angular-choice.mjs","names":[],"sources":["../../../projects/hyalo/choice/checkbox.ts","../../../projects/hyalo/choice/checkbox.html","../../../projects/hyalo/choice/radio.ts","../../../projects/hyalo/choice/radio-group.html","../../../projects/hyalo/choice/radio.html","../../../projects/hyalo/choice/switch.ts","../../../projects/hyalo/choice/switch.html"],"sourcesContent":["import {\r\n ChangeDetectionStrategy,\r\n Component,\r\n booleanAttribute,\r\n input,\r\n model,\r\n output,\r\n} from '@angular/core';\r\nimport type { FormCheckboxControl } from '@angular/forms/signals';\r\nimport { injectId } from '@hyalo/angular/core';\r\n\r\nimport { HyIcon } from '@hyalo/angular/icon';\r\n\r\n/**\r\n * A checkbox with a label. It wraps a real `<input type=\"checkbox\">`, so\r\n * Space toggles it, clicking the label works and forms see it.\r\n *\r\n * ```html\r\n * <hy-checkbox [formField]=\"form.terms\">I accept the terms</hy-checkbox>\r\n * <hy-checkbox [(checked)]=\"all\" [indeterminate]=\"some\">Select all</hy-checkbox>\r\n * ```\r\n */\r\n@Component({\r\n selector: 'hy-checkbox',\r\n imports: [HyIcon],\r\n changeDetection: ChangeDetectionStrategy.OnPush,\r\n host: {\r\n class: 'hy-choice hy-checkbox',\r\n '[attr.data-checked]': 'checked() || null',\r\n '[attr.data-indeterminate]': 'indeterminate() || null',\r\n '[attr.data-disabled]': 'disabled() || null',\r\n '[attr.data-invalid]': '(invalid() && touched()) || null',\r\n },\r\n templateUrl: './checkbox.html',\r\n styleUrl: './choice.css',\r\n})\r\nexport class HyCheckbox implements FormCheckboxControl {\r\n protected readonly descriptionId = injectId('checkbox-desc');\r\n\r\n /** Whether the box is checked. Two-way bindable and works with `[formField]`. */\r\n readonly checked = model(false);\r\n /** Shows a dash for a partly selected group. Cleared when the user toggles. */\r\n readonly indeterminate = model(false);\r\n /** Secondary text under the label. */\r\n readonly description = input<string>();\r\n readonly name = input('');\r\n readonly disabled = input(false, { transform: booleanAttribute });\r\n readonly required = input(false, { transform: booleanAttribute });\r\n readonly invalid = input(false, { transform: booleanAttribute });\r\n readonly touched = input(false, { transform: booleanAttribute });\r\n /** Emits when focus leaves the checkbox. */\r\n readonly touch = output<void>();\r\n\r\n protected onChange(event: Event): void {\r\n this.indeterminate.set(false);\r\n this.checked.set((event.target as HTMLInputElement).checked);\r\n }\r\n}\r\n","<label class=\"hy-choice__row\">\r\n <span class=\"hy-choice__control hy-checkbox__box\">\r\n <input\r\n type=\"checkbox\"\r\n class=\"hy-choice__input\"\r\n [name]=\"name()\"\r\n [checked]=\"checked()\"\r\n [indeterminate]=\"indeterminate()\"\r\n [disabled]=\"disabled()\"\r\n [required]=\"required()\"\r\n [attr.aria-invalid]=\"(invalid() && touched()) || null\"\r\n [attr.aria-describedby]=\"description() ? descriptionId : null\"\r\n (change)=\"onChange($event)\"\r\n (blur)=\"touch.emit()\"\r\n />\r\n <hy-icon\r\n class=\"hy-checkbox__mark\"\r\n [name]=\"indeterminate() ? 'minus' : 'check'\"\r\n [strokeWidth]=\"2.5\"\r\n />\r\n </span>\r\n <span class=\"hy-choice__label\"><ng-content /></span>\r\n</label>\r\n@if (description()) {\r\n <p class=\"hy-choice__description\" [id]=\"descriptionId\">{{ description() }}</p>\r\n}\r\n","import {\r\n ChangeDetectionStrategy,\r\n Component,\r\n booleanAttribute,\r\n computed,\r\n inject,\r\n input,\r\n model,\r\n output,\r\n} from '@angular/core';\r\nimport type { FormValueControl } from '@angular/forms/signals';\r\nimport { injectId } from '@hyalo/angular/core';\r\n\r\n/**\r\n * A group of radio buttons. Holds the value; the radios inside only say\r\n * which value they stand for.\r\n *\r\n * ```html\r\n * <hy-radio-group label=\"Delivery\" [formField]=\"form.delivery\">\r\n * <hy-radio value=\"standard\" description=\"3 to 5 days\">Standard</hy-radio>\r\n * <hy-radio value=\"express\">Express</hy-radio>\r\n * </hy-radio-group>\r\n * ```\r\n *\r\n * The radios are native inputs sharing one name, so arrow keys move the\r\n * selection the way the platform does, including in RTL.\r\n */\r\n@Component({\r\n selector: 'hy-radio-group',\r\n changeDetection: ChangeDetectionStrategy.OnPush,\r\n host: {\r\n class: 'hy-radio-group',\r\n role: 'radiogroup',\r\n '[attr.aria-labelledby]': 'label() ? labelId : null',\r\n '[attr.aria-invalid]': 'showsError() || null',\r\n '[attr.aria-required]': 'required() || null',\r\n '[attr.data-orientation]': 'orientation()',\r\n },\r\n templateUrl: './radio-group.html',\r\n styleUrl: './choice.css',\r\n})\r\nexport class HyRadioGroup<T> implements FormValueControl<T | undefined> {\r\n protected readonly labelId = injectId('radio-label');\r\n private readonly generatedName = injectId('radio');\r\n\r\n /** Selected value. Two-way bindable and works with `[formField]`. */\r\n readonly value = model<T | undefined>(undefined);\r\n /** Visible group label. */\r\n readonly label = input<string>();\r\n /** Shared input name. Generated when not set. */\r\n readonly name = input('');\r\n readonly orientation = input<'vertical' | 'horizontal'>('vertical');\r\n readonly disabled = input(false, { transform: booleanAttribute });\r\n readonly required = input(false, { transform: booleanAttribute });\r\n readonly invalid = input(false, { transform: booleanAttribute });\r\n readonly touched = input(false, { transform: booleanAttribute });\r\n readonly errors = input<readonly { readonly kind: string; readonly message?: string }[]>([]);\r\n /** Emits when focus leaves a radio. */\r\n readonly touch = output<void>();\r\n\r\n readonly groupName = computed(() => this.name() || this.generatedName);\r\n protected readonly showsError = computed(() => this.invalid() && this.touched());\r\n protected readonly errorMessage = computed(() => {\r\n const first = this.errors()[0];\r\n return first ? (first.message ?? first.kind) : '';\r\n });\r\n}\r\n\r\n/** One option inside a `hy-radio-group`. */\r\n@Component({\r\n selector: 'hy-radio',\r\n changeDetection: ChangeDetectionStrategy.OnPush,\r\n host: {\r\n class: 'hy-choice hy-radio',\r\n '[attr.data-checked]': 'checked() || null',\r\n '[attr.data-disabled]': 'isDisabled() || null',\r\n },\r\n templateUrl: './radio.html',\r\n styleUrl: './choice.css',\r\n})\r\nexport class HyRadio<T> {\r\n protected readonly group = inject<HyRadioGroup<T>>(HyRadioGroup);\r\n protected readonly descriptionId = injectId('radio-desc');\r\n\r\n /** The value this radio selects. */\r\n readonly value = input.required<T>();\r\n /** Secondary text under the label. */\r\n readonly description = input<string>();\r\n readonly disabled = input(false, { transform: booleanAttribute });\r\n\r\n protected readonly checked = computed(() => this.group.value() === this.value());\r\n protected readonly isDisabled = computed(() => this.disabled() || this.group.disabled());\r\n}\r\n","@if (label()) {\r\n <span class=\"hy-radio-group__label\" [id]=\"labelId\">{{ label() }}</span>\r\n}\r\n<div class=\"hy-radio-group__items\"><ng-content /></div>\r\n@if (showsError()) {\r\n <p class=\"hy-choice__error\">{{ errorMessage() }}</p>\r\n}\r\n","<label class=\"hy-choice__row\">\r\n <span class=\"hy-choice__control hy-radio__circle\">\r\n <input\r\n type=\"radio\"\r\n class=\"hy-choice__input\"\r\n [name]=\"group.groupName()\"\r\n [checked]=\"checked()\"\r\n [disabled]=\"isDisabled()\"\r\n [attr.aria-describedby]=\"description() ? descriptionId : null\"\r\n (change)=\"group.value.set(value())\"\r\n (blur)=\"group.touch.emit()\"\r\n />\r\n <span class=\"hy-radio__dot\" aria-hidden=\"true\"></span>\r\n </span>\r\n <span class=\"hy-choice__label\"><ng-content /></span>\r\n</label>\r\n@if (description()) {\r\n <p class=\"hy-choice__description\" [id]=\"descriptionId\">{{ description() }}</p>\r\n}\r\n","import {\r\n ChangeDetectionStrategy,\r\n Component,\r\n booleanAttribute,\r\n input,\r\n model,\r\n output,\r\n signal,\r\n} from '@angular/core';\r\nimport type { FormCheckboxControl } from '@angular/forms/signals';\r\nimport { injectId } from '@hyalo/angular/core';\r\nimport { rubberband } from '@hyalo/angular/motion';\r\n\r\n/** Movement before a press on the track turns into a drag, in px. */\r\nconst SLOP = 4;\r\n/** Track padding on each side, in px. Matches choice.css. */\r\nconst TRACK_PADDING = 2;\r\n/** Width of the pressed thumb, in rem. Matches choice.css. */\r\nconst PRESSED_THUMB = 1.5;\r\n\r\n/**\r\n * An on/off switch for settings that apply right away. For choices that\r\n * are submitted with a form, a checkbox is usually clearer.\r\n *\r\n * It is a native checkbox with `role=\"switch\"`, so screen readers say\r\n * \"on\" and \"off\" and Space toggles it. The thumb can also be dragged: it\r\n * follows the pointer, and lands on whichever side it is let go nearer.\r\n *\r\n * ```html\r\n * <hy-switch [(checked)]=\"notifications\">Email notifications</hy-switch>\r\n * ```\r\n */\r\n@Component({\r\n selector: 'hy-switch',\r\n changeDetection: ChangeDetectionStrategy.OnPush,\r\n host: {\r\n class: 'hy-choice hy-switch',\r\n '[attr.data-checked]': 'checked() || null',\r\n '[attr.data-disabled]': 'disabled() || null',\r\n },\r\n templateUrl: './switch.html',\r\n styleUrl: './choice.css',\r\n})\r\nexport class HySwitch implements FormCheckboxControl {\r\n protected readonly descriptionId = injectId('switch-desc');\r\n /** Physical thumb offset in px while it is dragged, otherwise null. */\r\n protected readonly drag = signal<number | null>(null);\r\n private press: { x: number; from: number; travel: number; dir: number; pos: number } | null =\r\n null;\r\n /** Where a finished drag landed, until the click it causes is handled. */\r\n private landed: boolean | null = null;\r\n\r\n /** Whether the switch is on. Two-way bindable and works with `[formField]`. */\r\n readonly checked = model(false);\r\n /** Secondary text under the label. */\r\n readonly description = input<string>();\r\n readonly name = input('');\r\n readonly disabled = input(false, { transform: booleanAttribute });\r\n readonly required = input(false, { transform: booleanAttribute });\r\n /** Emits when focus leaves the switch. */\r\n readonly touch = output<void>();\r\n\r\n protected onChange(event: Event): void {\r\n this.checked.set((event.target as HTMLInputElement).checked);\r\n }\r\n\r\n protected onDown(event: PointerEvent): void {\r\n if (this.disabled() || event.button !== 0) return;\r\n const track = event.currentTarget as HTMLElement;\r\n const rem = parseFloat(getComputedStyle(track.ownerDocument.documentElement).fontSize) || 16;\r\n const travel = track.clientWidth - 2 * TRACK_PADDING - PRESSED_THUMB * rem;\r\n this.press = {\r\n x: event.clientX,\r\n from: this.checked() ? travel : 0,\r\n travel,\r\n dir: getComputedStyle(track).direction === 'rtl' ? -1 : 1,\r\n pos: this.checked() ? travel : 0,\r\n };\r\n }\r\n\r\n protected onMove(event: PointerEvent): void {\r\n const press = this.press;\r\n if (!press) return;\r\n const moved = (event.clientX - press.x) * press.dir;\r\n if (this.drag() === null) {\r\n if (Math.abs(moved) < SLOP) return;\r\n try {\r\n (event.currentTarget as HTMLElement).setPointerCapture(event.pointerId);\r\n } catch {\r\n // The pointer is already gone; the drag still ends on pointerup.\r\n }\r\n }\r\n // Past either end the thumb resists instead of stopping dead.\r\n const raw = press.from + moved;\r\n const over = raw < 0 ? raw : raw > press.travel ? raw - press.travel : 0;\r\n press.pos = Math.min(Math.max(raw, 0), press.travel) + rubberband(over, press.travel);\r\n this.drag.set(press.pos * press.dir);\r\n }\r\n\r\n protected onUp(cancelled = false): void {\r\n const press = this.press;\r\n this.press = null;\r\n if (!press || this.drag() === null) return;\r\n this.drag.set(null);\r\n // Decided in logical position, so it is the same in both directions.\r\n const on = press.pos > press.travel / 2;\r\n if (cancelled) {\r\n this.checked.set(on);\r\n return;\r\n }\r\n // The release also clicks the label. That click applies the drag\r\n // instead of toggling; if no click comes, apply it anyway.\r\n this.landed = on;\r\n setTimeout(() => {\r\n if (this.landed === null) return;\r\n this.checked.set(this.landed);\r\n this.landed = null;\r\n });\r\n }\r\n\r\n protected onClick(event: MouseEvent): void {\r\n if (this.landed === null) return;\r\n event.preventDefault();\r\n this.checked.set(this.landed);\r\n this.landed = null;\r\n }\r\n}\r\n","<label class=\"hy-choice__row\">\r\n <span\r\n class=\"hy-choice__control hy-switch__track\"\r\n (pointerdown)=\"onDown($event)\"\r\n (pointermove)=\"onMove($event)\"\r\n (pointerup)=\"onUp()\"\r\n (pointercancel)=\"onUp(true)\"\r\n >\r\n <input\r\n type=\"checkbox\"\r\n role=\"switch\"\r\n class=\"hy-choice__input\"\r\n [name]=\"name()\"\r\n [checked]=\"checked()\"\r\n [disabled]=\"disabled()\"\r\n [required]=\"required()\"\r\n [attr.aria-checked]=\"checked()\"\r\n [attr.aria-describedby]=\"description() ? descriptionId : null\"\r\n (click)=\"onClick($event)\"\r\n (change)=\"onChange($event)\"\r\n (blur)=\"touch.emit()\"\r\n />\r\n <span\r\n class=\"hy-switch__thumb\"\r\n aria-hidden=\"true\"\r\n [attr.data-dragging]=\"drag() === null ? null : ''\"\r\n [style.--_drag.px]=\"drag()\"\r\n ></span>\r\n </span>\r\n <span class=\"hy-choice__label\"><ng-content /></span>\r\n</label>\r\n@if (description()) {\r\n <p class=\"hy-choice__description\" [id]=\"descriptionId\">{{ description() }}</p>\r\n}\r\n"],"mappings":"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"}
@@ -0,0 +1,40 @@
1
+ import hljs from "highlight.js/lib/core";
2
+ const languages = {
3
+ typescript: () => import("highlight.js/lib/languages/typescript"),
4
+ javascript: () => import("highlight.js/lib/languages/javascript"),
5
+ css: () => import("highlight.js/lib/languages/css"),
6
+ html: () => import("highlight.js/lib/languages/xml"),
7
+ json: () => import("highlight.js/lib/languages/json"),
8
+ bash: () => import("highlight.js/lib/languages/bash")
9
+ };
10
+ const pending = /* @__PURE__ */ new Map();
11
+ async function highlight(code, language) {
12
+ const name = {
13
+ ts: "typescript",
14
+ js: "javascript",
15
+ xml: "html",
16
+ sh: "bash"
17
+ }[language] ?? language;
18
+ if (!(name in languages)) return null;
19
+ let ready = pending.get(name);
20
+ if (!ready) {
21
+ const load = languages[name];
22
+ ready = load().then((module) => {
23
+ hljs.registerLanguage(name, module.default);
24
+ });
25
+ pending.set(name, ready);
26
+ }
27
+ try {
28
+ await ready;
29
+ return hljs.highlight(code, {
30
+ language: name,
31
+ ignoreIllegals: true
32
+ }).value;
33
+ } catch {
34
+ pending.delete(name);
35
+ return null;
36
+ }
37
+ }
38
+ export { highlight };
39
+
40
+ //# sourceMappingURL=hyalo-angular-code-block-highlight-B20d5C76.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"hyalo-angular-code-block-highlight-B20d5C76.mjs","names":[],"sources":["../../../projects/hyalo/code-block/highlight.ts"],"sourcesContent":["import hljs from 'highlight.js/lib/core';\r\nconst languages = {\r\n typescript: () => import('highlight.js/lib/languages/typescript'),\r\n javascript: () => import('highlight.js/lib/languages/javascript'),\r\n css: () => import('highlight.js/lib/languages/css'),\r\n html: () => import('highlight.js/lib/languages/xml'),\r\n json: () => import('highlight.js/lib/languages/json'),\r\n bash: () => import('highlight.js/lib/languages/bash'),\r\n};\r\nconst pending = new Map<string, Promise<void>>();\r\nexport async function highlight(code: string, language: string): Promise<string | null> {\r\n const name =\r\n ({ ts: 'typescript', js: 'javascript', xml: 'html', sh: 'bash' } as Record<string, string>)[\r\n language\r\n ] ?? language;\r\n if (!(name in languages)) return null;\r\n let ready = pending.get(name);\r\n if (!ready) {\r\n const load = languages[name as keyof typeof languages];\r\n ready = load().then((module) => {\r\n hljs.registerLanguage(name, module.default);\r\n });\r\n pending.set(name, ready);\r\n }\r\n try {\r\n await ready;\r\n return hljs.highlight(code, { language: name, ignoreIllegals: true }).value;\r\n } catch {\r\n pending.delete(name);\r\n return null;\r\n }\r\n}\r\n"],"mappings":";AACA,MAAM,YAAY;CAChB,kBAAkB,OAAO;CACzB,kBAAkB,OAAO;CACzB,WAAW,OAAO;CAClB,YAAY,OAAO;CACnB,YAAY,OAAO;CACnB,YAAY,OAAO;AACpB;AACD,MAAM,0BAAU,IAAI,IAAG;AACvB,eAAsB,UAAU,MAAc,UAAgB;CAC5D,MAAM,OACH;EAAE,IAAI;EAAc,IAAI;EAAc,KAAK;EAAQ,IAAI;CAAM,EAC5D,aACG;CACP,IAAI,EAAE,QAAQ,YAAY,OAAO;CACjC,IAAI,QAAQ,QAAQ,IAAI,IAAI;CAC5B,IAAI,CAAC,OAAO;EACV,MAAM,OAAO,UAAU;EACvB,QAAQ,KAAI,CAAE,CAAC,MAAM,WAAU;GAC7B,KAAK,iBAAiB,MAAM,OAAO,OAAO;EAC5C,CAAC;EACD,QAAQ,IAAI,MAAM,KAAK;CACzB;CACA,IAAI;EACF,MAAM;EACN,OAAO,KAAK,UAAU,MAAM;GAAE,UAAU;GAAM,gBAAgB;EAAI,CAAE,CAAC,CAAC;CACxE,QAAQ;EACN,QAAQ,OAAO,IAAI;EACnB,OAAO;CACT;AACF"}
@@ -0,0 +1,161 @@
1
+ import * as i0 from "@angular/core";
2
+ import { ChangeDetectionStrategy, Component, DestroyRef, afterNextRender, computed, effect, inject, input, signal } from "@angular/core";
3
+ import { HyCopy } from "@hyalo/angular/copy";
4
+ var HyCodeBlock = class HyCodeBlock {
5
+ code = input.required(...ngDevMode ? [{ debugName: "code" }] : /* istanbul ignore next */ []);
6
+ language = input("text", ...ngDevMode ? [{ debugName: "language" }] : /* istanbul ignore next */ []);
7
+ label = input("Code sample", ...ngDevMode ? [{ debugName: "label" }] : /* istanbul ignore next */ []);
8
+ copyable = input(true, ...ngDevMode ? [{ debugName: "copyable" }] : /* istanbul ignore next */ []);
9
+ samples = input([], ...ngDevMode ? [{ debugName: "samples" }] : /* istanbul ignore next */ []);
10
+ selected = signal(0, ...ngDevMode ? [{ debugName: "selected" }] : /* istanbul ignore next */ []);
11
+ active = computed(() => this.samples()[this.selected()] ?? {
12
+ code: this.code(),
13
+ language: this.language(),
14
+ label: this.label()
15
+ }, ...ngDevMode ? [{ debugName: "active" }] : /* istanbul ignore next */ []);
16
+ highlighted = signal(null, ...ngDevMode ? [{ debugName: "highlighted" }] : /* istanbul ignore next */ []);
17
+ ready = signal(false, ...ngDevMode ? [{ debugName: "ready" }] : /* istanbul ignore next */ []);
18
+ constructor() {
19
+ const destroy = inject(DestroyRef);
20
+ let generation = 0;
21
+ afterNextRender(() => this.ready.set(true));
22
+ effect(() => {
23
+ const sample = this.active(), ready = this.ready(), current = ++generation;
24
+ this.highlighted.set(null);
25
+ if (!ready || sample.language === "text") return;
26
+ import("./hyalo-angular-code-block-highlight-B20d5C76.mjs").then((module) => module.highlight(sample.code, sample.language)).then((html) => {
27
+ if (!destroy.destroyed && current === generation) this.highlighted.set(html);
28
+ }).catch(() => {});
29
+ });
30
+ }
31
+ static ɵfac = i0.ɵɵngDeclareFactory({
32
+ minVersion: "12.0.0",
33
+ version: "22.2.3",
34
+ ngImport: i0,
35
+ type: HyCodeBlock,
36
+ deps: [],
37
+ target: i0.ɵɵFactoryTarget.Component
38
+ });
39
+ static ɵcmp = i0.ɵɵngDeclareComponent({
40
+ minVersion: "17.0.0",
41
+ version: "22.2.3",
42
+ type: HyCodeBlock,
43
+ isStandalone: true,
44
+ selector: "hy-code-block",
45
+ inputs: {
46
+ code: {
47
+ classPropertyName: "code",
48
+ publicName: "code",
49
+ isSignal: true,
50
+ isRequired: true,
51
+ transformFunction: null
52
+ },
53
+ language: {
54
+ classPropertyName: "language",
55
+ publicName: "language",
56
+ isSignal: true,
57
+ isRequired: false,
58
+ transformFunction: null
59
+ },
60
+ label: {
61
+ classPropertyName: "label",
62
+ publicName: "label",
63
+ isSignal: true,
64
+ isRequired: false,
65
+ transformFunction: null
66
+ },
67
+ copyable: {
68
+ classPropertyName: "copyable",
69
+ publicName: "copyable",
70
+ isSignal: true,
71
+ isRequired: false,
72
+ transformFunction: null
73
+ },
74
+ samples: {
75
+ classPropertyName: "samples",
76
+ publicName: "samples",
77
+ isSignal: true,
78
+ isRequired: false,
79
+ transformFunction: null
80
+ }
81
+ },
82
+ ngImport: i0,
83
+ template: "<figure>\n <figcaption>\n <span\n >{{ label() }} <small>{{ active().language }}</small></span\n >\n @if (copyable()) {\n <hy-copy [text]=\"active().code\" [label]=\"'Copy ' + label()\" />\n }\n </figcaption>\n @if (samples().length > 1) {\n <div class=\"languages\" role=\"group\" aria-label=\"Code language\">\n @for (sample of samples(); track $index) {\n <button\n type=\"button\"\n [attr.aria-pressed]=\"selected() === $index\"\n (click)=\"selected.set($index)\"\n >\n {{ sample.label }}\n </button>\n }\n </div>\n }\n <pre\n tabindex=\"0\"\n [attr.aria-label]=\"active().label\"\n dir=\"ltr\"\n >@if (highlighted(); as html) {<code [innerHTML]=\"html\"></code>} @else {<code [textContent]=\"active().code\"></code>}</pre>\n</figure>\n",
84
+ styles: [":host{display:block;min-inline-size:0}figure{margin:0;border:1px solid var(--hy-line-strong);border-radius:var(--hy-radius-m);overflow:hidden;background:var(--hy-surface-2);color:var(--hy-ink)}figcaption{display:flex;justify-content:space-between;align-items:center;gap:1rem;padding:.5rem 1rem;border-block-end:1px solid var(--hy-line);font-size:.875rem}small{color:var(--hy-ink-3);margin-inline-start:.5rem}button{min-block-size:44px;padding:.5rem .75rem;background:var(--hy-surface-1);border:1px solid var(--hy-line);border-radius:var(--hy-radius-s);color:inherit;font:inherit;cursor:pointer}pre{margin:0;max-block-size:32rem;overflow:auto;padding:1rem;font:.8125rem/1.7 var(--hy-font-mono);tab-size:2}pre:focus-visible{outline:2px solid var(--hy-primary);outline-offset:-3px}.sr{position:absolute;inline-size:1px;block-size:1px;overflow:hidden;clip-path:inset(50%)}:is(button,a,input):focus-visible{outline:2px solid var(--hy-primary);outline-offset:3px}.languages{display:flex;gap:.5rem;padding:.5rem 1rem}.languages [aria-pressed=true]{background:var(--hy-primary-wash)}\n"],
85
+ dependencies: [{
86
+ kind: "component",
87
+ type: HyCopy,
88
+ selector: "hy-copy",
89
+ inputs: [
90
+ "text",
91
+ "label",
92
+ "copiedLabel",
93
+ "failedLabel"
94
+ ],
95
+ outputs: ["completed"]
96
+ }],
97
+ changeDetection: i0.ChangeDetectionStrategy.OnPush
98
+ });
99
+ };
100
+ i0.ɵɵngDeclareClassMetadata({
101
+ minVersion: "12.0.0",
102
+ version: "22.2.3",
103
+ ngImport: i0,
104
+ type: HyCodeBlock,
105
+ decorators: [{
106
+ type: Component,
107
+ args: [{
108
+ selector: "hy-code-block",
109
+ imports: [HyCopy],
110
+ changeDetection: ChangeDetectionStrategy.OnPush,
111
+ template: "<figure>\n <figcaption>\n <span\n >{{ label() }} <small>{{ active().language }}</small></span\n >\n @if (copyable()) {\n <hy-copy [text]=\"active().code\" [label]=\"'Copy ' + label()\" />\n }\n </figcaption>\n @if (samples().length > 1) {\n <div class=\"languages\" role=\"group\" aria-label=\"Code language\">\n @for (sample of samples(); track $index) {\n <button\n type=\"button\"\n [attr.aria-pressed]=\"selected() === $index\"\n (click)=\"selected.set($index)\"\n >\n {{ sample.label }}\n </button>\n }\n </div>\n }\n <pre\n tabindex=\"0\"\n [attr.aria-label]=\"active().label\"\n dir=\"ltr\"\n >@if (highlighted(); as html) {<code [innerHTML]=\"html\"></code>} @else {<code [textContent]=\"active().code\"></code>}</pre>\n</figure>\n",
112
+ styles: [":host{display:block;min-inline-size:0}figure{margin:0;border:1px solid var(--hy-line-strong);border-radius:var(--hy-radius-m);overflow:hidden;background:var(--hy-surface-2);color:var(--hy-ink)}figcaption{display:flex;justify-content:space-between;align-items:center;gap:1rem;padding:.5rem 1rem;border-block-end:1px solid var(--hy-line);font-size:.875rem}small{color:var(--hy-ink-3);margin-inline-start:.5rem}button{min-block-size:44px;padding:.5rem .75rem;background:var(--hy-surface-1);border:1px solid var(--hy-line);border-radius:var(--hy-radius-s);color:inherit;font:inherit;cursor:pointer}pre{margin:0;max-block-size:32rem;overflow:auto;padding:1rem;font:.8125rem/1.7 var(--hy-font-mono);tab-size:2}pre:focus-visible{outline:2px solid var(--hy-primary);outline-offset:-3px}.sr{position:absolute;inline-size:1px;block-size:1px;overflow:hidden;clip-path:inset(50%)}:is(button,a,input):focus-visible{outline:2px solid var(--hy-primary);outline-offset:3px}.languages{display:flex;gap:.5rem;padding:.5rem 1rem}.languages [aria-pressed=true]{background:var(--hy-primary-wash)}\n"]
113
+ }]
114
+ }],
115
+ ctorParameters: () => [],
116
+ propDecorators: {
117
+ code: [{
118
+ type: i0.Input,
119
+ args: [{
120
+ isSignal: true,
121
+ alias: "code",
122
+ required: true
123
+ }]
124
+ }],
125
+ language: [{
126
+ type: i0.Input,
127
+ args: [{
128
+ isSignal: true,
129
+ alias: "language",
130
+ required: false
131
+ }]
132
+ }],
133
+ label: [{
134
+ type: i0.Input,
135
+ args: [{
136
+ isSignal: true,
137
+ alias: "label",
138
+ required: false
139
+ }]
140
+ }],
141
+ copyable: [{
142
+ type: i0.Input,
143
+ args: [{
144
+ isSignal: true,
145
+ alias: "copyable",
146
+ required: false
147
+ }]
148
+ }],
149
+ samples: [{
150
+ type: i0.Input,
151
+ args: [{
152
+ isSignal: true,
153
+ alias: "samples",
154
+ required: false
155
+ }]
156
+ }]
157
+ }
158
+ });
159
+ export { HyCodeBlock };
160
+
161
+ //# sourceMappingURL=hyalo-angular-code-block.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"hyalo-angular-code-block.mjs","names":[],"sources":["../../../projects/hyalo/code-block/code-block.ts","../../../projects/hyalo/code-block/code-block.html"],"sourcesContent":["import {\r\n ChangeDetectionStrategy,\r\n Component,\r\n DestroyRef,\r\n afterNextRender,\r\n computed,\r\n effect,\r\n inject,\r\n input,\r\n signal,\r\n} from '@angular/core';\r\nimport { HyCopy } from '@hyalo/angular/copy';\r\nexport interface HyCodeSample {\r\n readonly code: string;\r\n readonly language: string;\r\n readonly label: string;\r\n}\r\n@Component({\r\n selector: 'hy-code-block',\r\n imports: [HyCopy],\r\n changeDetection: ChangeDetectionStrategy.OnPush,\r\n templateUrl: './code-block.html',\r\n styleUrl: './code-block.css',\r\n})\r\nexport class HyCodeBlock {\r\n readonly code = input.required<string>();\r\n readonly language = input('text');\r\n readonly label = input('Code sample');\r\n readonly copyable = input(true);\r\n readonly samples = input<readonly HyCodeSample[]>([]);\r\n protected readonly selected = signal(0);\r\n protected readonly active = computed(\r\n () =>\r\n this.samples()[this.selected()] ?? {\r\n code: this.code(),\r\n language: this.language(),\r\n label: this.label(),\r\n },\r\n );\r\n protected readonly highlighted = signal<string | null>(null);\r\n private readonly ready = signal(false);\r\n constructor() {\r\n const destroy = inject(DestroyRef);\r\n let generation = 0;\r\n afterNextRender(() => this.ready.set(true));\r\n effect(() => {\r\n const sample = this.active(),\r\n ready = this.ready(),\r\n current = ++generation;\r\n this.highlighted.set(null);\r\n if (!ready || sample.language === 'text') return;\r\n void import('./highlight')\r\n .then((module) => module.highlight(sample.code, sample.language))\r\n .then((html) => {\r\n if (!destroy.destroyed && current === generation) this.highlighted.set(html);\r\n })\r\n .catch(() => {\r\n /* Plain source remains usable when the optional highlighter is unavailable. */\r\n });\r\n });\r\n }\r\n}\r\n","<figure>\n <figcaption>\n <span\n >{{ label() }} <small>{{ active().language }}</small></span\n >\n @if (copyable()) {\n <hy-copy [text]=\"active().code\" [label]=\"'Copy ' + label()\" />\n }\n </figcaption>\n @if (samples().length > 1) {\n <div class=\"languages\" role=\"group\" aria-label=\"Code language\">\n @for (sample of samples(); track $index) {\n <button\n type=\"button\"\n [attr.aria-pressed]=\"selected() === $index\"\n (click)=\"selected.set($index)\"\n >\n {{ sample.label }}\n </button>\n }\n </div>\n }\n <pre\n tabindex=\"0\"\n [attr.aria-label]=\"active().label\"\n dir=\"ltr\"\n >@if (highlighted(); as html) {<code [innerHTML]=\"html\"></code>} @else {<code [textContent]=\"active().code\"></code>}</pre>\n</figure>\n"],"mappings":"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"}
@@ -0,0 +1,193 @@
1
+ import { Combobox, ComboboxPopup, ComboboxWidget } from "@angular/aria/combobox";
2
+ import { Listbox, Option } from "@angular/aria/listbox";
3
+ import { injectId, normalizeSearch } from "@hyalo/angular/core";
4
+ import { DIALOG_DATA, Dialog, DialogRef } from "@angular/cdk/dialog";
5
+ import * as i0 from "@angular/core";
6
+ import { ChangeDetectionStrategy, Component, Injectable, computed, inject, signal } from "@angular/core";
7
+ var HyCommandPanel = class HyCommandPanel {
8
+ data = inject(DIALOG_DATA);
9
+ ref = inject(DialogRef);
10
+ id = injectId("command");
11
+ query = signal("", ...ngDevMode ? [{ debugName: "query" }] : /* istanbul ignore next */ []);
12
+ indexed = this.data.items.map((item) => ({
13
+ item,
14
+ text: normalizeSearch([
15
+ item.label,
16
+ item.description,
17
+ ...item.keywords ?? []
18
+ ].join(" "))
19
+ }));
20
+ matches = computed(() => {
21
+ const words = normalizeSearch(this.query()).split(/\s+/).filter(Boolean);
22
+ return this.indexed.filter((entry) => words.every((word) => entry.text.includes(word))).map((entry) => entry.item);
23
+ }, ...ngDevMode ? [{ debugName: "matches" }] : /* istanbul ignore next */ []);
24
+ results = computed(() => this.matches().slice(0, 50), ...ngDevMode ? [{ debugName: "results" }] : /* istanbul ignore next */ []);
25
+ selected = signal([], ...ngDevMode ? [{ debugName: "selected" }] : /* istanbul ignore next */ []);
26
+ pick(values) {
27
+ const item = values[values.length - 1];
28
+ if (item && !item.disabled) this.ref.close(item);
29
+ }
30
+ search(event) {
31
+ this.query.set(event.target.value);
32
+ }
33
+ choose(item) {
34
+ if (!item.disabled) this.ref.close(item);
35
+ }
36
+ dismiss(event) {
37
+ event.preventDefault();
38
+ event.stopPropagation();
39
+ this.close();
40
+ }
41
+ close() {
42
+ this.ref.close();
43
+ }
44
+ static ɵfac = i0.ɵɵngDeclareFactory({
45
+ minVersion: "12.0.0",
46
+ version: "22.2.3",
47
+ ngImport: i0,
48
+ type: HyCommandPanel,
49
+ deps: [],
50
+ target: i0.ɵɵFactoryTarget.Component
51
+ });
52
+ static ɵcmp = i0.ɵɵngDeclareComponent({
53
+ minVersion: "17.0.0",
54
+ version: "22.2.3",
55
+ type: HyCommandPanel,
56
+ isStandalone: true,
57
+ selector: "hy-command-panel",
58
+ ngImport: i0,
59
+ template: "<div class=\"search\">\n <input\n ngCombobox\n #combobox=\"ngCombobox\"\n type=\"search\"\n autocomplete=\"off\"\n spellcheck=\"false\"\n [alwaysExpanded]=\"true\"\n (keydown.escape)=\"dismiss($event)\"\n [attr.aria-label]=\"data.label ?? 'Command search'\"\n [placeholder]=\"data.placeholder ?? 'Search pages and actions'\"\n [value]=\"query()\"\n (input)=\"search($event)\"\n />\n <button type=\"button\" aria-label=\"Close command palette\" (click)=\"close()\">Esc</button>\n</div>\n<ng-template ngComboboxPopup [combobox]=\"combobox\">\n <ul\n ngComboboxWidget\n ngListbox\n #listbox=\"ngListbox\"\n focusMode=\"activedescendant\"\n selectionMode=\"explicit\"\n [activeDescendant]=\"listbox.activeDescendant()\"\n [value]=\"selected()\"\n (valueChange)=\"pick($event)\"\n [attr.aria-label]=\"data.label ?? 'Commands'\"\n >\n @for (item of results(); track item.id) {\n <li ngOption [value]=\"item\" [label]=\"item.label\" [disabled]=\"!!item.disabled\">\n <span>\n @if (item.group) {\n <small>{{ item.group }}</small>\n }\n <strong>{{ item.label }}</strong>\n @if (item.description) {\n <span class=\"description\">{{ item.description }}</span>\n }\n </span>\n @if (item.shortcut) {\n <kbd>{{ item.shortcut }}</kbd>\n }\n </li>\n }\n </ul>\n</ng-template>\n<div class=\"status\" role=\"status\">\n @if (!results().length) {\n {{ data.emptyLabel ?? 'No matching commands' }}\n } @else {\n {{ matches().length }} results\n @if (matches().length > 50) {\n · showing the first 50\n }\n }\n</div>\n",
60
+ styles: [":host{display:block;overflow:hidden;border:1px solid var(--hy-line-strong);border-radius:var(--hy-radius-l);background:var(--hy-surface-1);color:var(--hy-ink);box-shadow:var(--hy-glass-shadow-thick)}.search{display:flex;align-items:center;gap:.75rem;padding:.75rem 1rem;border-block-end:1px solid var(--hy-line);border-start-start-radius:inherit;border-start-end-radius:inherit}.search:focus-within{outline:2px solid var(--hy-primary);outline-offset:-3px}input{flex:1;min-inline-size:0;min-block-size:44px;background:transparent;border:0;color:inherit;font:inherit;outline:none}button{font:.75rem var(--hy-font-mono);color:var(--hy-ink-2);border:1px solid var(--hy-line);border-radius:var(--hy-radius-s);background:var(--hy-surface-2);min-inline-size:44px;min-block-size:44px;cursor:pointer}ul{list-style:none;margin:0;padding:.5rem;max-block-size:min(24rem,55dvh);overflow:auto;overscroll-behavior:contain}li{display:flex;justify-content:space-between;align-items:center;gap:1rem;min-block-size:44px;padding:.75rem;border-radius:var(--hy-radius-s);cursor:pointer}li[aria-selected=true]{background:var(--hy-primary-wash)}li[aria-disabled=true]{opacity:.45;cursor:default}strong{font-size:.9375rem}small,.description{display:block;color:var(--hy-ink-2);font-size:.75rem}small{margin-block-end:.25rem}kbd{font:.75rem var(--hy-font-mono);color:var(--hy-ink-2)}.status{border-block-start:1px solid var(--hy-line);padding:.75rem 1rem;color:var(--hy-ink-2);font-size:.75rem}:is(button,a):focus-visible{outline:2px solid var(--hy-primary);outline-offset:3px}\n"],
61
+ dependencies: [
62
+ {
63
+ kind: "directive",
64
+ type: Combobox,
65
+ selector: "[ngCombobox]",
66
+ inputs: [
67
+ "disabled",
68
+ "readonly",
69
+ "softDisabled",
70
+ "alwaysExpanded",
71
+ "tabindex",
72
+ "expanded",
73
+ "value",
74
+ "inlineSuggestion"
75
+ ],
76
+ outputs: ["expandedChange", "valueChange"],
77
+ exportAs: ["ngCombobox"]
78
+ },
79
+ {
80
+ kind: "directive",
81
+ type: ComboboxPopup,
82
+ selector: "ng-template[ngComboboxPopup]",
83
+ inputs: ["combobox", "popupType"],
84
+ exportAs: ["ngComboboxPopup"]
85
+ },
86
+ {
87
+ kind: "directive",
88
+ type: ComboboxWidget,
89
+ selector: "[ngComboboxWidget]",
90
+ inputs: ["activeDescendant"],
91
+ exportAs: ["ngComboboxWidget"]
92
+ },
93
+ {
94
+ kind: "directive",
95
+ type: Listbox,
96
+ selector: "[ngListbox]",
97
+ inputs: [
98
+ "id",
99
+ "orientation",
100
+ "multi",
101
+ "wrap",
102
+ "softDisabled",
103
+ "focusMode",
104
+ "selectionMode",
105
+ "typeaheadDelay",
106
+ "disabled",
107
+ "readonly",
108
+ "tabindex",
109
+ "value"
110
+ ],
111
+ outputs: ["valueChange"],
112
+ exportAs: ["ngListbox"]
113
+ },
114
+ {
115
+ kind: "directive",
116
+ type: Option,
117
+ selector: "[ngOption]",
118
+ inputs: [
119
+ "id",
120
+ "value",
121
+ "disabled",
122
+ "label"
123
+ ],
124
+ exportAs: ["ngOption"]
125
+ }
126
+ ],
127
+ changeDetection: i0.ChangeDetectionStrategy.OnPush
128
+ });
129
+ };
130
+ i0.ɵɵngDeclareClassMetadata({
131
+ minVersion: "12.0.0",
132
+ version: "22.2.3",
133
+ ngImport: i0,
134
+ type: HyCommandPanel,
135
+ decorators: [{
136
+ type: Component,
137
+ args: [{
138
+ selector: "hy-command-panel",
139
+ imports: [
140
+ Combobox,
141
+ ComboboxPopup,
142
+ ComboboxWidget,
143
+ Listbox,
144
+ Option
145
+ ],
146
+ changeDetection: ChangeDetectionStrategy.OnPush,
147
+ template: "<div class=\"search\">\n <input\n ngCombobox\n #combobox=\"ngCombobox\"\n type=\"search\"\n autocomplete=\"off\"\n spellcheck=\"false\"\n [alwaysExpanded]=\"true\"\n (keydown.escape)=\"dismiss($event)\"\n [attr.aria-label]=\"data.label ?? 'Command search'\"\n [placeholder]=\"data.placeholder ?? 'Search pages and actions'\"\n [value]=\"query()\"\n (input)=\"search($event)\"\n />\n <button type=\"button\" aria-label=\"Close command palette\" (click)=\"close()\">Esc</button>\n</div>\n<ng-template ngComboboxPopup [combobox]=\"combobox\">\n <ul\n ngComboboxWidget\n ngListbox\n #listbox=\"ngListbox\"\n focusMode=\"activedescendant\"\n selectionMode=\"explicit\"\n [activeDescendant]=\"listbox.activeDescendant()\"\n [value]=\"selected()\"\n (valueChange)=\"pick($event)\"\n [attr.aria-label]=\"data.label ?? 'Commands'\"\n >\n @for (item of results(); track item.id) {\n <li ngOption [value]=\"item\" [label]=\"item.label\" [disabled]=\"!!item.disabled\">\n <span>\n @if (item.group) {\n <small>{{ item.group }}</small>\n }\n <strong>{{ item.label }}</strong>\n @if (item.description) {\n <span class=\"description\">{{ item.description }}</span>\n }\n </span>\n @if (item.shortcut) {\n <kbd>{{ item.shortcut }}</kbd>\n }\n </li>\n }\n </ul>\n</ng-template>\n<div class=\"status\" role=\"status\">\n @if (!results().length) {\n {{ data.emptyLabel ?? 'No matching commands' }}\n } @else {\n {{ matches().length }} results\n @if (matches().length > 50) {\n · showing the first 50\n }\n }\n</div>\n",
148
+ styles: [":host{display:block;overflow:hidden;border:1px solid var(--hy-line-strong);border-radius:var(--hy-radius-l);background:var(--hy-surface-1);color:var(--hy-ink);box-shadow:var(--hy-glass-shadow-thick)}.search{display:flex;align-items:center;gap:.75rem;padding:.75rem 1rem;border-block-end:1px solid var(--hy-line);border-start-start-radius:inherit;border-start-end-radius:inherit}.search:focus-within{outline:2px solid var(--hy-primary);outline-offset:-3px}input{flex:1;min-inline-size:0;min-block-size:44px;background:transparent;border:0;color:inherit;font:inherit;outline:none}button{font:.75rem var(--hy-font-mono);color:var(--hy-ink-2);border:1px solid var(--hy-line);border-radius:var(--hy-radius-s);background:var(--hy-surface-2);min-inline-size:44px;min-block-size:44px;cursor:pointer}ul{list-style:none;margin:0;padding:.5rem;max-block-size:min(24rem,55dvh);overflow:auto;overscroll-behavior:contain}li{display:flex;justify-content:space-between;align-items:center;gap:1rem;min-block-size:44px;padding:.75rem;border-radius:var(--hy-radius-s);cursor:pointer}li[aria-selected=true]{background:var(--hy-primary-wash)}li[aria-disabled=true]{opacity:.45;cursor:default}strong{font-size:.9375rem}small,.description{display:block;color:var(--hy-ink-2);font-size:.75rem}small{margin-block-end:.25rem}kbd{font:.75rem var(--hy-font-mono);color:var(--hy-ink-2)}.status{border-block-start:1px solid var(--hy-line);padding:.75rem 1rem;color:var(--hy-ink-2);font-size:.75rem}:is(button,a):focus-visible{outline:2px solid var(--hy-primary);outline-offset:3px}\n"]
149
+ }]
150
+ }]
151
+ });
152
+ var HyCommand = class HyCommand {
153
+ dialog = inject(Dialog);
154
+ open(config) {
155
+ return this.dialog.open(HyCommandPanel, {
156
+ data: config,
157
+ ariaLabel: config.label ?? "Command palette",
158
+ autoFocus: "input",
159
+ restoreFocus: true,
160
+ width: "36rem",
161
+ maxWidth: "calc(100vw - 2rem)",
162
+ maxHeight: "calc(100dvh - 2rem)"
163
+ });
164
+ }
165
+ static ɵfac = i0.ɵɵngDeclareFactory({
166
+ minVersion: "12.0.0",
167
+ version: "22.2.3",
168
+ ngImport: i0,
169
+ type: HyCommand,
170
+ deps: [],
171
+ target: i0.ɵɵFactoryTarget.Injectable
172
+ });
173
+ static ɵprov = i0.ɵɵngDeclareInjectable({
174
+ minVersion: "12.0.0",
175
+ version: "22.2.3",
176
+ ngImport: i0,
177
+ type: HyCommand,
178
+ providedIn: "root"
179
+ });
180
+ };
181
+ i0.ɵɵngDeclareClassMetadata({
182
+ minVersion: "12.0.0",
183
+ version: "22.2.3",
184
+ ngImport: i0,
185
+ type: HyCommand,
186
+ decorators: [{
187
+ type: Injectable,
188
+ args: [{ providedIn: "root" }]
189
+ }]
190
+ });
191
+ export { HyCommand, HyCommandPanel };
192
+
193
+ //# sourceMappingURL=hyalo-angular-command.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"hyalo-angular-command.mjs","names":[],"sources":["../../../projects/hyalo/command/command.ts","../../../projects/hyalo/command/command.html"],"sourcesContent":["import { Combobox, ComboboxPopup, ComboboxWidget } from '@angular/aria/combobox';\nimport { Listbox, Option } from '@angular/aria/listbox';\nimport { normalizeSearch } from '@hyalo/angular/core';\nimport { Dialog, DIALOG_DATA, DialogRef } from '@angular/cdk/dialog';\nimport {\n ChangeDetectionStrategy,\n Component,\n Injectable,\n computed,\n inject,\n signal,\n} from '@angular/core';\nimport { injectId } from '@hyalo/angular/core';\nexport interface HyCommandItem<T = unknown> {\n readonly id: string;\n readonly label: string;\n readonly value: T;\n readonly description?: string;\n readonly keywords?: readonly string[];\n readonly group?: string;\n readonly shortcut?: string;\n readonly disabled?: boolean;\n}\nexport interface HyCommandConfig<T = unknown> {\n readonly items: readonly HyCommandItem<T>[];\n readonly label?: string;\n readonly placeholder?: string;\n readonly emptyLabel?: string;\n}\n@Component({\n selector: 'hy-command-panel',\n imports: [Combobox, ComboboxPopup, ComboboxWidget, Listbox, Option],\n changeDetection: ChangeDetectionStrategy.OnPush,\n templateUrl: './command.html',\n styleUrl: './command.css',\n})\nexport class HyCommandPanel {\n protected readonly data = inject(DIALOG_DATA) as HyCommandConfig;\n private readonly ref = inject<DialogRef<HyCommandItem>>(DialogRef);\n protected readonly id = injectId('command');\n protected readonly query = signal('');\n private readonly indexed = this.data.items.map((item) => ({\n item,\n text: normalizeSearch([item.label, item.description, ...(item.keywords ?? [])].join(' ')),\n }));\n protected readonly matches = computed(() => {\n const words = normalizeSearch(this.query()).split(/\\s+/).filter(Boolean);\n return this.indexed\n .filter((entry) => words.every((word) => entry.text.includes(word)))\n .map((entry) => entry.item);\n });\n protected readonly results = computed(() => this.matches().slice(0, 50));\n protected readonly selected = signal<HyCommandItem[]>([]);\n protected pick(values: readonly HyCommandItem[]): void {\n const item = values[values.length - 1];\n if (item && !item.disabled) this.ref.close(item);\n }\n protected search(event: Event): void {\n this.query.set((event.target as HTMLInputElement).value);\n }\n protected choose(item: HyCommandItem): void {\n if (!item.disabled) this.ref.close(item);\n }\n protected dismiss(event: Event): void {\n event.preventDefault();\n event.stopPropagation();\n this.close();\n }\n protected close(): void {\n this.ref.close();\n }\n}\n\n@Injectable({ providedIn: 'root' })\nexport class HyCommand {\n private readonly dialog = inject(Dialog);\n open<T>(config: HyCommandConfig<T>): DialogRef<HyCommandItem<T>> {\n return this.dialog.open<HyCommandItem<T>>(HyCommandPanel, {\n data: config,\n ariaLabel: config.label ?? 'Command palette',\n autoFocus: 'input',\n restoreFocus: true,\n width: '36rem',\n maxWidth: 'calc(100vw - 2rem)',\n maxHeight: 'calc(100dvh - 2rem)',\n });\n }\n}\n","<div class=\"search\">\n <input\n ngCombobox\n #combobox=\"ngCombobox\"\n type=\"search\"\n autocomplete=\"off\"\n spellcheck=\"false\"\n [alwaysExpanded]=\"true\"\n (keydown.escape)=\"dismiss($event)\"\n [attr.aria-label]=\"data.label ?? 'Command search'\"\n [placeholder]=\"data.placeholder ?? 'Search pages and actions'\"\n [value]=\"query()\"\n (input)=\"search($event)\"\n />\n <button type=\"button\" aria-label=\"Close command palette\" (click)=\"close()\">Esc</button>\n</div>\n<ng-template ngComboboxPopup [combobox]=\"combobox\">\n <ul\n ngComboboxWidget\n ngListbox\n #listbox=\"ngListbox\"\n focusMode=\"activedescendant\"\n selectionMode=\"explicit\"\n [activeDescendant]=\"listbox.activeDescendant()\"\n [value]=\"selected()\"\n (valueChange)=\"pick($event)\"\n [attr.aria-label]=\"data.label ?? 'Commands'\"\n >\n @for (item of results(); track item.id) {\n <li ngOption [value]=\"item\" [label]=\"item.label\" [disabled]=\"!!item.disabled\">\n <span>\n @if (item.group) {\n <small>{{ item.group }}</small>\n }\n <strong>{{ item.label }}</strong>\n @if (item.description) {\n <span class=\"description\">{{ item.description }}</span>\n }\n </span>\n @if (item.shortcut) {\n <kbd>{{ item.shortcut }}</kbd>\n }\n </li>\n }\n </ul>\n</ng-template>\n<div class=\"status\" role=\"status\">\n @if (!results().length) {\n {{ data.emptyLabel ?? 'No matching commands' }}\n } @else {\n {{ matches().length }} results\n @if (matches().length > 50) {\n · showing the first 50\n }\n }\n</div>\n"],"mappings":"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"}
@@ -0,0 +1,138 @@
1
+ import { Clipboard } from "@angular/cdk/clipboard";
2
+ import * as i0 from "@angular/core";
3
+ import { ChangeDetectionStrategy, Component, DestroyRef, computed, inject, input, output, signal } from "@angular/core";
4
+ var HyCopy = class HyCopy {
5
+ text = input.required(...ngDevMode ? [{ debugName: "text" }] : /* istanbul ignore next */ []);
6
+ label = input("Copy", ...ngDevMode ? [{ debugName: "label" }] : /* istanbul ignore next */ []);
7
+ copiedLabel = input("Copied", ...ngDevMode ? [{ debugName: "copiedLabel" }] : /* istanbul ignore next */ []);
8
+ failedLabel = input("Copy failed. Select and copy the text.", ...ngDevMode ? [{ debugName: "failedLabel" }] : /* istanbul ignore next */ []);
9
+ completed = output();
10
+ status = signal("", ...ngDevMode ? [{ debugName: "status" }] : /* istanbul ignore next */ []);
11
+ clipboard = inject(Clipboard);
12
+ timer;
13
+ copied = computed(() => this.status() === this.copiedLabel(), ...ngDevMode ? [{ debugName: "copied" }] : /* istanbul ignore next */ []);
14
+ constructor() {
15
+ inject(DestroyRef).onDestroy(() => clearTimeout(this.timer));
16
+ }
17
+ copy() {
18
+ clearTimeout(this.timer);
19
+ const success = this.clipboard.copy(this.text());
20
+ this.status.set(success ? this.copiedLabel() : this.failedLabel());
21
+ this.completed.emit(success);
22
+ this.timer = setTimeout(() => this.status.set(""), 2e3);
23
+ }
24
+ static ɵfac = i0.ɵɵngDeclareFactory({
25
+ minVersion: "12.0.0",
26
+ version: "22.2.3",
27
+ ngImport: i0,
28
+ type: HyCopy,
29
+ deps: [],
30
+ target: i0.ɵɵFactoryTarget.Component
31
+ });
32
+ static ɵcmp = i0.ɵɵngDeclareComponent({
33
+ minVersion: "17.1.0",
34
+ version: "22.2.3",
35
+ type: HyCopy,
36
+ isStandalone: true,
37
+ selector: "hy-copy",
38
+ inputs: {
39
+ text: {
40
+ classPropertyName: "text",
41
+ publicName: "text",
42
+ isSignal: true,
43
+ isRequired: true,
44
+ transformFunction: null
45
+ },
46
+ label: {
47
+ classPropertyName: "label",
48
+ publicName: "label",
49
+ isSignal: true,
50
+ isRequired: false,
51
+ transformFunction: null
52
+ },
53
+ copiedLabel: {
54
+ classPropertyName: "copiedLabel",
55
+ publicName: "copiedLabel",
56
+ isSignal: true,
57
+ isRequired: false,
58
+ transformFunction: null
59
+ },
60
+ failedLabel: {
61
+ classPropertyName: "failedLabel",
62
+ publicName: "failedLabel",
63
+ isSignal: true,
64
+ isRequired: false,
65
+ transformFunction: null
66
+ }
67
+ },
68
+ outputs: { completed: "completed" },
69
+ ngImport: i0,
70
+ template: `<button type="button" (click)="copy()" [attr.aria-label]="label()">
71
+ {{ copied() ? copiedLabel() : label() }}</button
72
+ ><span class="sr" role="status">{{ status() }}</span
73
+ ><ng-content />`,
74
+ isInline: true,
75
+ styles: [":host{display:inline-flex;align-items:center;gap:.5rem}button{min-block-size:44px;border:1px solid var(--hy-line);background:var(--hy-surface-1);color:var(--hy-ink);border-radius:var(--hy-radius-s);font:inherit;padding:.5rem .75rem;cursor:pointer}button:focus-visible{outline:2px solid var(--hy-primary);outline-offset:2px}.sr{position:absolute;inline-size:1px;block-size:1px;clip-path:inset(50%);overflow:hidden}\n"],
76
+ changeDetection: i0.ChangeDetectionStrategy.OnPush
77
+ });
78
+ };
79
+ i0.ɵɵngDeclareClassMetadata({
80
+ minVersion: "12.0.0",
81
+ version: "22.2.3",
82
+ ngImport: i0,
83
+ type: HyCopy,
84
+ decorators: [{
85
+ type: Component,
86
+ args: [{
87
+ selector: "hy-copy",
88
+ changeDetection: ChangeDetectionStrategy.OnPush,
89
+ template: `<button type="button" (click)="copy()" [attr.aria-label]="label()">
90
+ {{ copied() ? copiedLabel() : label() }}</button
91
+ ><span class="sr" role="status">{{ status() }}</span
92
+ ><ng-content />`,
93
+ styles: [":host{display:inline-flex;align-items:center;gap:.5rem}button{min-block-size:44px;border:1px solid var(--hy-line);background:var(--hy-surface-1);color:var(--hy-ink);border-radius:var(--hy-radius-s);font:inherit;padding:.5rem .75rem;cursor:pointer}button:focus-visible{outline:2px solid var(--hy-primary);outline-offset:2px}.sr{position:absolute;inline-size:1px;block-size:1px;clip-path:inset(50%);overflow:hidden}\n"]
94
+ }]
95
+ }],
96
+ ctorParameters: () => [],
97
+ propDecorators: {
98
+ text: [{
99
+ type: i0.Input,
100
+ args: [{
101
+ isSignal: true,
102
+ alias: "text",
103
+ required: true
104
+ }]
105
+ }],
106
+ label: [{
107
+ type: i0.Input,
108
+ args: [{
109
+ isSignal: true,
110
+ alias: "label",
111
+ required: false
112
+ }]
113
+ }],
114
+ copiedLabel: [{
115
+ type: i0.Input,
116
+ args: [{
117
+ isSignal: true,
118
+ alias: "copiedLabel",
119
+ required: false
120
+ }]
121
+ }],
122
+ failedLabel: [{
123
+ type: i0.Input,
124
+ args: [{
125
+ isSignal: true,
126
+ alias: "failedLabel",
127
+ required: false
128
+ }]
129
+ }],
130
+ completed: [{
131
+ type: i0.Output,
132
+ args: ["completed"]
133
+ }]
134
+ }
135
+ });
136
+ export { HyCopy };
137
+
138
+ //# sourceMappingURL=hyalo-angular-copy.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"hyalo-angular-copy.mjs","names":[],"sources":["../../../projects/hyalo/copy/copy.ts"],"sourcesContent":["import { Clipboard } from '@angular/cdk/clipboard';\nimport {\n ChangeDetectionStrategy,\n Component,\n DestroyRef,\n computed,\n inject,\n input,\n output,\n signal,\n} from '@angular/core';\n@Component({\n selector: 'hy-copy',\n changeDetection: ChangeDetectionStrategy.OnPush,\n template: `<button type=\"button\" (click)=\"copy()\" [attr.aria-label]=\"label()\">\n {{ copied() ? copiedLabel() : label() }}</button\n ><span class=\"sr\" role=\"status\">{{ status() }}</span\n ><ng-content />`,\n styleUrl: './copy.css',\n})\nexport class HyCopy {\n readonly text = input.required<string>();\n readonly label = input('Copy');\n readonly copiedLabel = input('Copied');\n readonly failedLabel = input('Copy failed. Select and copy the text.');\n readonly completed = output<boolean>();\n protected readonly status = signal('');\n private readonly clipboard = inject(Clipboard);\n private timer?: ReturnType<typeof setTimeout>;\n protected readonly copied = computed(() => this.status() === this.copiedLabel());\n constructor() {\n inject(DestroyRef).onDestroy(() => clearTimeout(this.timer));\n }\n copy(): void {\n clearTimeout(this.timer);\n const success = this.clipboard.copy(this.text());\n this.status.set(success ? this.copiedLabel() : this.failedLabel());\n this.completed.emit(success);\n this.timer = setTimeout(() => this.status.set(''), 2000);\n }\n}\n"],"mappings":";;;AAoBA,IAAa,SAAb,MAAa,OAAM;CACR,OAAO,MAAM,SAAkB,GAAA,YAAA,CAAA,EAAA,WAAA,OAAA,CAAA,+BAAA,CAAA,CAAA;CAC/B,QAAQ,MAAM,QAAO,GAAA,YAAA,CAAA,EAAA,WAAA,QAAA,CAAA,+BAAA,CAAA,CAAA;CACrB,cAAc,MAAM,UAAS,GAAA,YAAA,CAAA,EAAA,WAAA,cAAA,CAAA,+BAAA,CAAA,CAAA;CAC7B,cAAc,MAAM,0CAAyC,GAAA,YAAA,CAAA,EAAA,WAAA,cAAA,CAAA,+BAAA,CAAA,CAAA;CAC7D,YAAY,OAAM;CACR,SAAS,OAAO,IAAG,GAAA,YAAA,CAAA,EAAA,WAAA,SAAA,CAAA,+BAAA,CAAA,CAAA;CACrB,YAAY,OAAO,SAAS;CACrC;CACW,SAAS,eAAe,KAAK,OAAM,MAAO,KAAK,YAAW,GAAG,GAAA,YAAA,CAAA,EAAA,WAAA,SAAA,CAAA,+BAAA,CAAA,CAAA;CAChF,cAAA;EACE,OAAO,UAAU,CAAC,CAAC,gBAAgB,aAAa,KAAK,KAAK,CAAC;CAC7D;CACA,OAAI;EACF,aAAa,KAAK,KAAK;EACvB,MAAM,UAAU,KAAK,UAAU,KAAK,KAAK,KAAI,CAAE;EAC/C,KAAK,OAAO,IAAI,UAAU,KAAK,YAAW,IAAK,KAAK,YAAW,CAAE;EACjE,KAAK,UAAU,KAAK,OAAO;EAC3B,KAAK,QAAQ,iBAAiB,KAAK,OAAO,IAAI,EAAE,GAAG,GAAI;CACzD;CAnBW,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,OAAA;IAAA,mBAAA;IAAA,YAAA;IAAA,UAAA;IAAA,YAAA;IAAA,mBAAA;GAAA;GAAA,aAAA;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,SAAA,EAAA,WAAA,YAAA;EAAA,UAAA;EAAA,UANP;;;;EAGQ,UAAA;EAAA,QAAA,CAAA,iaAAA;EAAA,iBAAA,GAAA,wBAAA;CAAA,CAAA;;AAGP,GAAA,yBAAA;CAAA,YAAA;CAAA,SAAA;CAAA,UAAA;CAAA,MAAA;CAAM,YAAA,CAAA;EATlB,MAAA;EACW,MAAA,CAAA;GAAA,UAAA;GAAS,iBACF,wBAAwB;GAAM,UACrC;;;;GAGQ,QAAA,CAAA,iaAAA;EAAA,CAAA"}