circletone.mjs 61 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851
  1. import * as i0 from '@angular/core';
  2. import { Component, ChangeDetectionStrategy, Input, EventEmitter, Output, Pipe, Injectable, inject, DestroyRef, ContentChildren, Directive, HostListener, forwardRef, ChangeDetectorRef, signal, ViewChild } from '@angular/core';
  3. import { NgClass, AsyncPipe, KeyValuePipe, JsonPipe } from '@angular/common';
  4. import * as i1 from '@angular/platform-browser';
  5. import { RouterLink } from '@angular/router';
  6. import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
  7. import { withLatestFrom, debounceTime, skip, BehaviorSubject, filter, Subject, fromEvent } from 'rxjs';
  8. import * as i1$1 from '@angular/forms';
  9. import { NG_VALUE_ACCESSOR, ControlContainer, FormGroupDirective } from '@angular/forms';
  10. import { debounceTime as debounceTime$1, map, startWith, tap } from 'rxjs/operators';
  11. /**
  12. * Used for some components to determine colouring of various elements. Relates to CSS classes to facilitate dev's life
  13. */
  14. var TypeEnum;
  15. (function (TypeEnum) {
  16. TypeEnum["PRIMARY"] = "primary";
  17. TypeEnum["SECONDARY"] = "secondary";
  18. TypeEnum["TERTIARY"] = "tertiary";
  19. TypeEnum["SUCCESS"] = "success";
  20. TypeEnum["WARNING"] = "warning";
  21. TypeEnum["ERROR"] = "error";
  22. })(TypeEnum || (TypeEnum = {}));
  23. /**
  24. * Used for some components to determine sizing of various elements. Relates to 'tailwind' classes to facilitate dev's life
  25. */
  26. var SizeEnum;
  27. (function (SizeEnum) {
  28. /** extra-small */
  29. SizeEnum["XS"] = "xs";
  30. /** small */
  31. SizeEnum["SM"] = "sm";
  32. /** default size */
  33. SizeEnum["BASE"] = "base";
  34. /** large */
  35. SizeEnum["LG"] = "lg";
  36. /** extra-large */
  37. SizeEnum["XL"] = "xl";
  38. })(SizeEnum || (SizeEnum = {}));
  39. /**
  40. * Used for some components to determine the variance of diverse elements.
  41. */
  42. var VariantEnum;
  43. (function (VariantEnum) {
  44. /** produces a non-styled element */
  45. VariantEnum["BLANK"] = "blank";
  46. /** produces a solid element */
  47. VariantEnum["SOLID"] = "solid";
  48. /** produces a bordered element */
  49. VariantEnum["OUTLINE"] = "outline";
  50. /** produces a solid-gradient element */
  51. VariantEnum["GRADIENT"] = "gradient";
  52. })(VariantEnum || (VariantEnum = {}));
  53. class IconComponent {
  54. constructor() {
  55. this.icon = '';
  56. this.fill = 'currentColor';
  57. this.strokeWidth = 1.5;
  58. this.strokeColor = 'currentColor';
  59. this.size = SizeEnum.BASE;
  60. this.variant = VariantEnum.OUTLINE;
  61. }
  62. ngOnInit() {
  63. this.strokeColor = this.getFormattedColor(this.strokeColor);
  64. this.fill = this.getFormattedColor(this.fill);
  65. }
  66. get iconPath() {
  67. const icon = this.variant === VariantEnum.SOLID ? `${this.icon}-solid` : this.icon;
  68. return `/assets/icons.svg#${icon}`;
  69. }
  70. getFormattedColor(color) {
  71. if (color.startsWith('--')) {
  72. const rgbValue = getComputedStyle(document.documentElement).getPropertyValue(color).trim();
  73. return `rgb(${rgbValue})`;
  74. }
  75. return color;
  76. }
  77. static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.2", ngImport: i0, type: IconComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
  78. static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "17.3.2", type: IconComponent, isStandalone: true, selector: "ct-icon", inputs: { icon: "icon", fill: "fill", strokeWidth: "strokeWidth", strokeColor: "strokeColor", size: "size", variant: "variant" }, ngImport: i0, template: "<svg\n [attr.fill]=\"variant === 'solid' ? fill : 'none'\"\n [attr.stroke-width]=\"variant === 'outline' ? strokeWidth : 0\"\n [attr.stroke]=\"strokeColor\"\n class=\"flex\"\n [class.size-3]=\"size === 'xs'\"\n [class.size-4]=\"size === 'sm'\"\n [class.size-5]=\"size === 'base'\"\n [class.size-6]=\"size === 'lg'\"\n [class.size-8]=\"size === 'xl'\">\n <use [attr.xlink:href]=\"iconPath\"></use>\n</svg>\n", changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
  79. }
  80. i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.2", ngImport: i0, type: IconComponent, decorators: [{
  81. type: Component,
  82. args: [{ selector: 'ct-icon', standalone: true, imports: [NgClass], changeDetection: ChangeDetectionStrategy.OnPush, template: "<svg\n [attr.fill]=\"variant === 'solid' ? fill : 'none'\"\n [attr.stroke-width]=\"variant === 'outline' ? strokeWidth : 0\"\n [attr.stroke]=\"strokeColor\"\n class=\"flex\"\n [class.size-3]=\"size === 'xs'\"\n [class.size-4]=\"size === 'sm'\"\n [class.size-5]=\"size === 'base'\"\n [class.size-6]=\"size === 'lg'\"\n [class.size-8]=\"size === 'xl'\">\n <use [attr.xlink:href]=\"iconPath\"></use>\n</svg>\n" }]
  83. }], propDecorators: { icon: [{
  84. type: Input
  85. }], fill: [{
  86. type: Input
  87. }], strokeWidth: [{
  88. type: Input
  89. }], strokeColor: [{
  90. type: Input
  91. }], size: [{
  92. type: Input
  93. }], variant: [{
  94. type: Input
  95. }] } });
  96. /**
  97. * This is the ButtonComponent, widely used among other components
  98. */
  99. class ButtonComponent {
  100. constructor() {
  101. this.iconPosition = 'left';
  102. this.fullSize = false;
  103. this.size = 'base';
  104. this.type = 'primary';
  105. this.variant = 'solid';
  106. }
  107. get cssClassmap() {
  108. return {
  109. [`text-on-${this.type} dark:text-on-${this.type}-dark`]: this.variant === VariantEnum.SOLID || this.variant === VariantEnum.GRADIENT,
  110. [`text-neutral-950 dark:text-neutral-50 hover:text-${this.type}-dark dark:hover:text-${this.type}`]: this.variant === VariantEnum.GRADIENT || this.variant === VariantEnum.BLANK,
  111. [`bg-${this.type} dark:bg-${this.type}-dark hover:bg-${this.type}-variant hover:dark:bg-${this.type}-variant-dark`]: this.variant === VariantEnum.SOLID,
  112. [`from-${this.type}-variant from-30% to-${this.type} bg-gradient-to-tl hover:bg-gradient-to-br dark:from-${this.type}-variant-dark dark:to-${this.type}-dark`]: this.variant === VariantEnum.GRADIENT,
  113. [`border border-2 border-${this.type} hover:border-${this.type}-variant dark:border-${this.type}-dark`]: this.variant === VariantEnum.OUTLINE,
  114. 'px-3 py-2': (this.size === SizeEnum.XS || this.size === SizeEnum.SM) && !this.hasJustIcon(),
  115. 'px-5 py-2.5': (this.size === SizeEnum.BASE || this.size === SizeEnum.LG) && !this.hasJustIcon(),
  116. 'px-6 py-3': this.size === SizeEnum.XL && !this.hasJustIcon(),
  117. 'p-2': this.hasJustIcon() && this.variant !== 'blank',
  118. 'text-xs': this.size === SizeEnum.XS,
  119. 'text-sm': this.size === SizeEnum.SM || this.size === SizeEnum.BASE,
  120. 'text-base': this.size === SizeEnum.LG || this.size === SizeEnum.XL,
  121. 'w-full': this.fullSize,
  122. };
  123. }
  124. hasJustIcon() {
  125. return this.icon !== undefined && this.text === undefined;
  126. }
  127. static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.2", ngImport: i0, type: ButtonComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
  128. static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "17.3.2", type: ButtonComponent, isStandalone: true, selector: "ct-button", inputs: { text: "text", icon: "icon", iconPosition: "iconPosition", fullSize: "fullSize", size: "size", type: "type", variant: "variant" }, ngImport: i0, template: "<button class=\"flex flex-row items-center justify-center gap-1.5 rounded-md font-medium\" [ngClass]=\"cssClassmap\">\n @if (icon) {\n <ct-icon class=\"flex\" [size]=\"size\" [icon]=\"icon\" />\n }\n @if (text) {\n <span [class.order-first]=\"iconPosition === 'right'\">\n {{ text }}\n </span>\n }\n</button>\n", dependencies: [{ kind: "directive", type: NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "component", type: IconComponent, selector: "ct-icon", inputs: ["icon", "fill", "strokeWidth", "strokeColor", "size", "variant"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
  129. }
  130. i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.2", ngImport: i0, type: ButtonComponent, decorators: [{
  131. type: Component,
  132. args: [{ selector: 'ct-button', standalone: true, imports: [NgClass, IconComponent], changeDetection: ChangeDetectionStrategy.OnPush, template: "<button class=\"flex flex-row items-center justify-center gap-1.5 rounded-md font-medium\" [ngClass]=\"cssClassmap\">\n @if (icon) {\n <ct-icon class=\"flex\" [size]=\"size\" [icon]=\"icon\" />\n }\n @if (text) {\n <span [class.order-first]=\"iconPosition === 'right'\">\n {{ text }}\n </span>\n }\n</button>\n" }]
  133. }], propDecorators: { text: [{
  134. type: Input
  135. }], icon: [{
  136. type: Input
  137. }], iconPosition: [{
  138. type: Input
  139. }], fullSize: [{
  140. type: Input
  141. }], size: [{
  142. type: Input
  143. }], type: [{
  144. type: Input
  145. }], variant: [{
  146. type: Input
  147. }] } });
  148. /**
  149. * The alert component is responsible to show alerts for diverse elements. Including `FormErrorComponent` among others.
  150. */
  151. class AlertComponent {
  152. constructor() {
  153. this.dismissable = false;
  154. this.fullSize = true;
  155. this.text = '';
  156. this.type = TypeEnum.PRIMARY;
  157. this.variant = VariantEnum.SOLID;
  158. this.withIcon = true;
  159. this.dismiss = new EventEmitter();
  160. }
  161. get icon() {
  162. switch (this.type) {
  163. case TypeEnum.PRIMARY:
  164. case TypeEnum.SECONDARY:
  165. return 'information-circle';
  166. case TypeEnum.ERROR:
  167. return 'exclamation-triangle';
  168. case TypeEnum.WARNING:
  169. return 'exclamation-circle';
  170. case TypeEnum.SUCCESS:
  171. return 'check-circle';
  172. default:
  173. return '';
  174. }
  175. }
  176. static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.2", ngImport: i0, type: AlertComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
  177. static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "17.3.2", type: AlertComponent, isStandalone: true, selector: "ct-alert", inputs: { dismissable: "dismissable", fullSize: "fullSize", text: "text", type: "type", variant: "variant", withIcon: "withIcon" }, outputs: { dismiss: "dismiss" }, ngImport: i0, template: "<div\n class=\"mb-4 flex flex-row items-center gap-1 rounded-lg\"\n [class.w-fit]=\"!fullSize\"\n [class.w-full]=\"fullSize\"\n role=\"alert\"\n [ngClass]=\"{\n 'bg-surface-variant dark:bg-surface-variant-dark text-on-surface dark:text-on-surface-dark':\n type === 'primary' && variant === 'solid',\n 'bg-warning dark:bg-warning-dark text-on-warning dark:text-on-warning-dark':\n type === 'warning' && variant === 'solid',\n 'bg-error dark:bg-error-dark text-on-error dark:text-on-error-dark': type === 'error' && variant === 'solid',\n 'bg-success dark:bg-success-dark text-on-success dark:text-on-success-dark':\n type === 'success' && variant === 'solid',\n border: variant === 'outline',\n 'border-surface-variant dark:border-surface-variant-dark': type === 'primary' && variant === 'outline',\n 'border-warning dark:border-warning-dark': type === 'warning' && variant === 'outline',\n 'border-error dark:border-error-dark': type === 'error' && variant === 'outline',\n 'border-success dark:border-success-dark': type === 'success' && variant === 'outline',\n 'px-4 py-2': variant !== 'blank'\n }\">\n @if (withIcon) {\n <ct-icon [icon]=\"this.icon\" />\n }\n <span class=\"grow text-sm font-semibold\">{{ text }}</span>\n @if (dismissable) {\n <ct-button icon=\"x-mark\" size=\"sm\" variant=\"blank\" [type]=\"type\" (click)=\"dismiss.emit()\" />\n }\n</div>\n", dependencies: [{ kind: "component", type: IconComponent, selector: "ct-icon", inputs: ["icon", "fill", "strokeWidth", "strokeColor", "size", "variant"] }, { kind: "component", type: ButtonComponent, selector: "ct-button", inputs: ["text", "icon", "iconPosition", "fullSize", "size", "type", "variant"] }, { kind: "directive", type: NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
  178. }
  179. i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.2", ngImport: i0, type: AlertComponent, decorators: [{
  180. type: Component,
  181. args: [{ selector: 'ct-alert', standalone: true, imports: [IconComponent, ButtonComponent, NgClass], changeDetection: ChangeDetectionStrategy.OnPush, template: "<div\n class=\"mb-4 flex flex-row items-center gap-1 rounded-lg\"\n [class.w-fit]=\"!fullSize\"\n [class.w-full]=\"fullSize\"\n role=\"alert\"\n [ngClass]=\"{\n 'bg-surface-variant dark:bg-surface-variant-dark text-on-surface dark:text-on-surface-dark':\n type === 'primary' && variant === 'solid',\n 'bg-warning dark:bg-warning-dark text-on-warning dark:text-on-warning-dark':\n type === 'warning' && variant === 'solid',\n 'bg-error dark:bg-error-dark text-on-error dark:text-on-error-dark': type === 'error' && variant === 'solid',\n 'bg-success dark:bg-success-dark text-on-success dark:text-on-success-dark':\n type === 'success' && variant === 'solid',\n border: variant === 'outline',\n 'border-surface-variant dark:border-surface-variant-dark': type === 'primary' && variant === 'outline',\n 'border-warning dark:border-warning-dark': type === 'warning' && variant === 'outline',\n 'border-error dark:border-error-dark': type === 'error' && variant === 'outline',\n 'border-success dark:border-success-dark': type === 'success' && variant === 'outline',\n 'px-4 py-2': variant !== 'blank'\n }\">\n @if (withIcon) {\n <ct-icon [icon]=\"this.icon\" />\n }\n <span class=\"grow text-sm font-semibold\">{{ text }}</span>\n @if (dismissable) {\n <ct-button icon=\"x-mark\" size=\"sm\" variant=\"blank\" [type]=\"type\" (click)=\"dismiss.emit()\" />\n }\n</div>\n" }]
  182. }], propDecorators: { dismissable: [{
  183. type: Input
  184. }], fullSize: [{
  185. type: Input
  186. }], text: [{
  187. type: Input,
  188. args: [{ required: true }]
  189. }], type: [{
  190. type: Input
  191. }], variant: [{
  192. type: Input
  193. }], withIcon: [{
  194. type: Input
  195. }], dismiss: [{
  196. type: Output
  197. }] } });
  198. class SafeImagePipe {
  199. constructor(sanitizer) {
  200. this.sanitizer = sanitizer;
  201. }
  202. transform(value, type = 'image/webp') {
  203. const imageBase64 = `data:${type};base64,${value}`;
  204. return this.sanitizer.bypassSecurityTrustUrl(imageBase64);
  205. }
  206. static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.2", ngImport: i0, type: SafeImagePipe, deps: [{ token: i1.DomSanitizer }], target: i0.ɵɵFactoryTarget.Pipe }); }
  207. static { this.ɵpipe = i0.ɵɵngDeclarePipe({ minVersion: "14.0.0", version: "17.3.2", ngImport: i0, type: SafeImagePipe, isStandalone: true, name: "safeImage" }); }
  208. }
  209. i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.2", ngImport: i0, type: SafeImagePipe, decorators: [{
  210. type: Pipe,
  211. args: [{
  212. name: 'safeImage',
  213. standalone: true,
  214. }]
  215. }], ctorParameters: () => [{ type: i1.DomSanitizer }] });
  216. class AvatarComponent {
  217. constructor() {
  218. this.picture = '';
  219. this.title = '';
  220. this.titleInitials = '';
  221. }
  222. ngOnInit() {
  223. this.titleInitials = this.title
  224. .split(' ')
  225. .map(word => word[0]?.toLocaleUpperCase())
  226. .splice(0, 2)
  227. .join('');
  228. }
  229. static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.2", ngImport: i0, type: AvatarComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
  230. static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "17.3.2", type: AvatarComponent, isStandalone: true, selector: "ct-avatar", inputs: { picture: "picture", title: "title" }, ngImport: i0, template: "@if (picture) {\n <img\n [src]=\"picture\"\n alt=\"{{ title }}\"\n class=\"size-16 rounded-full border-2 border-primary object-cover dark:border-primary-dark\" />\n} @else {\n <div\n class=\"size-16 truncate text-ellipsis rounded-full border border-primary bg-primary-container p-4 text-on-primary-container dark:bg-primary-container-dark dark:text-on-primary-container-dark\">\n <span class=\"text-2xl font-medium\"> {{ titleInitials }}</span>\n </div>\n}\n", changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
  231. }
  232. i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.2", ngImport: i0, type: AvatarComponent, decorators: [{
  233. type: Component,
  234. args: [{ selector: 'ct-avatar', standalone: true, imports: [IconComponent, SafeImagePipe], changeDetection: ChangeDetectionStrategy.OnPush, template: "@if (picture) {\n <img\n [src]=\"picture\"\n alt=\"{{ title }}\"\n class=\"size-16 rounded-full border-2 border-primary object-cover dark:border-primary-dark\" />\n} @else {\n <div\n class=\"size-16 truncate text-ellipsis rounded-full border border-primary bg-primary-container p-4 text-on-primary-container dark:bg-primary-container-dark dark:text-on-primary-container-dark\">\n <span class=\"text-2xl font-medium\"> {{ titleInitials }}</span>\n </div>\n}\n" }]
  235. }], propDecorators: { picture: [{
  236. type: Input
  237. }], title: [{
  238. type: Input
  239. }] } });
  240. class HeaderComponent {
  241. constructor() {
  242. this.title = '';
  243. }
  244. static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.2", ngImport: i0, type: HeaderComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
  245. static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "17.3.2", type: HeaderComponent, isStandalone: true, selector: "ct-header", inputs: { title: "title" }, ngImport: i0, template: "<div\n class=\"flex h-14 w-full items-center justify-between bg-gradient-to-b from-surface to-primary px-4 py-2 dark:from-surface-variant-dark dark:to-primary-container-dark\">\n <div class=\"flex grow font-logo\">{{ title }}</div>\n <ng-content />\n</div>\n", changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
  246. }
  247. i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.2", ngImport: i0, type: HeaderComponent, decorators: [{
  248. type: Component,
  249. args: [{ selector: 'ct-header', standalone: true, imports: [], changeDetection: ChangeDetectionStrategy.OnPush, template: "<div\n class=\"flex h-14 w-full items-center justify-between bg-gradient-to-b from-surface to-primary px-4 py-2 dark:from-surface-variant-dark dark:to-primary-container-dark\">\n <div class=\"flex grow font-logo\">{{ title }}</div>\n <ng-content />\n</div>\n" }]
  250. }], propDecorators: { title: [{
  251. type: Input
  252. }] } });
  253. class MenuItemComponent {
  254. constructor() {
  255. this.text = '';
  256. this.link = '';
  257. this.type = 'internal';
  258. this.icon = undefined;
  259. this.iconSize = SizeEnum.BASE;
  260. this.iconAlone = false;
  261. this.iconDirection = 'horizontal';
  262. }
  263. static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.2", ngImport: i0, type: MenuItemComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
  264. static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "17.3.2", type: MenuItemComponent, isStandalone: true, selector: "ct-menu-item", inputs: { text: "text", link: "link", type: "type", icon: "icon", iconSize: "iconSize", iconAlone: "iconAlone", iconDirection: "iconDirection" }, ngImport: i0, template: "<a\n [routerLink]=\"(type === 'internal' && link)! || null\"\n [attr.href]=\"type === 'external' && link\"\n class=\"block rounded-md px-4 py-2 text-on-surface hover:bg-primary/25 dark:text-on-surface-dark dark:hover:bg-primary-dark/25\">\n <span\n class=\"flex items-center gap-3\"\n [class.flex-row]=\"iconDirection === 'horizontal'\"\n [class.flex-col]=\"iconDirection === 'vertical'\">\n @if (icon) {\n <ct-icon [icon]=\"icon\" variant=\"solid\" size=\"xl\" />\n }\n @if (text && !iconAlone) {\n <span>bbb {{ text }}</span>\n }\n </span>\n</a>\n", dependencies: [{ kind: "directive", type: RouterLink, selector: "[routerLink]", inputs: ["target", "queryParams", "fragment", "queryParamsHandling", "state", "info", "relativeTo", "preserveFragment", "skipLocationChange", "replaceUrl", "routerLink"] }, { kind: "component", type: IconComponent, selector: "ct-icon", inputs: ["icon", "fill", "strokeWidth", "strokeColor", "size", "variant"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
  265. }
  266. i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.2", ngImport: i0, type: MenuItemComponent, decorators: [{
  267. type: Component,
  268. args: [{ selector: 'ct-menu-item', standalone: true, imports: [RouterLink, IconComponent, ButtonComponent], changeDetection: ChangeDetectionStrategy.OnPush, template: "<a\n [routerLink]=\"(type === 'internal' && link)! || null\"\n [attr.href]=\"type === 'external' && link\"\n class=\"block rounded-md px-4 py-2 text-on-surface hover:bg-primary/25 dark:text-on-surface-dark dark:hover:bg-primary-dark/25\">\n <span\n class=\"flex items-center gap-3\"\n [class.flex-row]=\"iconDirection === 'horizontal'\"\n [class.flex-col]=\"iconDirection === 'vertical'\">\n @if (icon) {\n <ct-icon [icon]=\"icon\" variant=\"solid\" size=\"xl\" />\n }\n @if (text && !iconAlone) {\n <span>bbb {{ text }}</span>\n }\n </span>\n</a>\n" }]
  269. }], propDecorators: { text: [{
  270. type: Input
  271. }], link: [{
  272. type: Input,
  273. args: [{ required: true }]
  274. }], type: [{
  275. type: Input,
  276. args: [{ required: true }]
  277. }], icon: [{
  278. type: Input
  279. }], iconSize: [{
  280. type: Input
  281. }], iconAlone: [{
  282. type: Input
  283. }], iconDirection: [{
  284. type: Input
  285. }] } });
  286. class AccordionRegistryService {
  287. constructor() {
  288. this.accordions = new Map();
  289. }
  290. register(id, element) {
  291. this.accordions.set(id, element);
  292. }
  293. get(id) {
  294. return this.accordions.get(id);
  295. }
  296. unregister(id) {
  297. this.accordions.delete(id);
  298. }
  299. getItem(accordion, itemId) {
  300. const accordionObject = this.accordions.get(accordion);
  301. return accordionObject.accordionItems.find(item => item.id === itemId);
  302. }
  303. openItem(accordion, itemId) {
  304. this.accordions
  305. .get(accordion)
  306. ?.accordionItems.find(item => item.id === itemId)
  307. ?.isOpen.next(true);
  308. }
  309. static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.2", ngImport: i0, type: AccordionRegistryService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
  310. static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "17.3.2", ngImport: i0, type: AccordionRegistryService, providedIn: 'any' }); }
  311. }
  312. i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.2", ngImport: i0, type: AccordionRegistryService, decorators: [{
  313. type: Injectable,
  314. args: [{ providedIn: 'any' }]
  315. }] });
  316. class AccordionComponent {
  317. constructor() {
  318. this.destroyRef = inject(DestroyRef);
  319. this.accordionRegistryService = inject(AccordionRegistryService);
  320. this.label = '';
  321. this.policy = 'collapse';
  322. this.gap = 0;
  323. this.parentAccordion = '';
  324. this.parentTrigger = '';
  325. }
  326. ngAfterViewInit() {
  327. this.accordionItems.forEach(accordionItem => {
  328. accordionItem.toggle
  329. .pipe(takeUntilDestroyed(this.destroyRef), withLatestFrom(accordionItem.isOpen), debounceTime(10))
  330. .subscribe(([_, isOpen]) => {
  331. accordionItem.isOpen.next(!isOpen);
  332. });
  333. accordionItem.isOpen.pipe(takeUntilDestroyed(this.destroyRef), skip(1), debounceTime(10)).subscribe(isOpen => {
  334. if (isOpen) {
  335. if (this.parentTrigger) {
  336. this.accordionRegistryService.getItem(this.parentAccordion, this.parentTrigger)?.isOpen.next(true);
  337. }
  338. if (this.policy === 'collapse') {
  339. this.accordionItems.forEach(otherAccordionItem => {
  340. if (accordionItem.id !== otherAccordionItem.id && otherAccordionItem.isOpen) {
  341. otherAccordionItem.isOpen.next(false);
  342. }
  343. });
  344. }
  345. }
  346. });
  347. });
  348. this.accordionRegistryService.register(this.id, this);
  349. }
  350. ngOnDestroy() {
  351. this.accordionRegistryService.unregister(this.id);
  352. }
  353. closePanes() {
  354. this.accordionItems.forEach(accordionItem => accordionItem.isOpen.next(false));
  355. }
  356. static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.2", ngImport: i0, type: AccordionComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
  357. static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "17.3.2", type: AccordionComponent, isStandalone: true, selector: "ct-accordion", inputs: { label: "label", id: "id", policy: "policy", gap: "gap", parentAccordion: "parentAccordion", parentTrigger: "parentTrigger" }, queries: [{ propertyName: "accordionItems", predicate: AccordionItemComponent }], ngImport: i0, template: "<div class=\"flex flex-col gap-{{ gap }}\">\n <ng-content></ng-content>\n</div>\n", changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
  358. }
  359. i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.2", ngImport: i0, type: AccordionComponent, decorators: [{
  360. type: Component,
  361. args: [{ selector: 'ct-accordion', standalone: true, imports: [AsyncPipe, IconComponent], changeDetection: ChangeDetectionStrategy.OnPush, template: "<div class=\"flex flex-col gap-{{ gap }}\">\n <ng-content></ng-content>\n</div>\n" }]
  362. }], propDecorators: { label: [{
  363. type: Input
  364. }], id: [{
  365. type: Input,
  366. args: [{ required: true }]
  367. }], policy: [{
  368. type: Input
  369. }], gap: [{
  370. type: Input
  371. }], parentAccordion: [{
  372. type: Input
  373. }], parentTrigger: [{
  374. type: Input
  375. }], accordionItems: [{
  376. type: ContentChildren,
  377. args: [AccordionItemComponent]
  378. }] } });
  379. class AccordionItemComponent {
  380. constructor() {
  381. this.destroyRef = inject(DestroyRef);
  382. this.id = '';
  383. this.label = '';
  384. this.isOpen = new BehaviorSubject(false);
  385. this.toggle = new EventEmitter();
  386. }
  387. ngAfterViewInit() {
  388. this.isOpen
  389. .pipe(takeUntilDestroyed(this.destroyRef), skip(1), filter(isOpen => !isOpen))
  390. .subscribe(() => {
  391. this.accordions.forEach(accordion => {
  392. accordion.closePanes();
  393. });
  394. });
  395. }
  396. static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.2", ngImport: i0, type: AccordionItemComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
  397. static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "17.3.2", type: AccordionItemComponent, isStandalone: true, selector: "ct-accordion-item", inputs: { id: "id", label: "label", isOpen: "isOpen" }, outputs: { toggle: "toggle" }, queries: [{ propertyName: "accordions", predicate: AccordionComponent }], ngImport: i0, template: "<div\n tabindex=\"0\"\n class=\"flex cursor-pointer flex-row items-center justify-between gap-1.5 bg-surface px-4 py-2 text-on-surface hover:bg-primary/50 dark:bg-surface-dark dark:text-on-surface-dark hover:dark:bg-surface-variant-dark\"\n [class.rounded-t-md]=\"isOpen | async\"\n [class.rounded-md]=\"(isOpen | async) === false\"\n (click)=\"toggle.emit()\">\n <span class=\"grow\">{{ label }}</span>\n <ct-icon size=\"sm\" [icon]=\"(isOpen | async) ? 'chevron-up' : 'chevron-down'\" />\n</div>\n@if (isOpen | async) {\n <div class=\"flex flex-col rounded-b-md bg-surface/35 p-4 dark:bg-surface-dark/50\">\n <ng-content></ng-content>\n </div>\n}\n", dependencies: [{ kind: "component", type: IconComponent, selector: "ct-icon", inputs: ["icon", "fill", "strokeWidth", "strokeColor", "size", "variant"] }, { kind: "pipe", type: AsyncPipe, name: "async" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
  398. }
  399. i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.2", ngImport: i0, type: AccordionItemComponent, decorators: [{
  400. type: Component,
  401. args: [{ selector: 'ct-accordion-item', standalone: true, imports: [IconComponent, AsyncPipe], changeDetection: ChangeDetectionStrategy.OnPush, template: "<div\n tabindex=\"0\"\n class=\"flex cursor-pointer flex-row items-center justify-between gap-1.5 bg-surface px-4 py-2 text-on-surface hover:bg-primary/50 dark:bg-surface-dark dark:text-on-surface-dark hover:dark:bg-surface-variant-dark\"\n [class.rounded-t-md]=\"isOpen | async\"\n [class.rounded-md]=\"(isOpen | async) === false\"\n (click)=\"toggle.emit()\">\n <span class=\"grow\">{{ label }}</span>\n <ct-icon size=\"sm\" [icon]=\"(isOpen | async) ? 'chevron-up' : 'chevron-down'\" />\n</div>\n@if (isOpen | async) {\n <div class=\"flex flex-col rounded-b-md bg-surface/35 p-4 dark:bg-surface-dark/50\">\n <ng-content></ng-content>\n </div>\n}\n" }]
  402. }], propDecorators: { id: [{
  403. type: Input,
  404. args: [{ required: true }]
  405. }], label: [{
  406. type: Input
  407. }], isOpen: [{
  408. type: Input
  409. }], toggle: [{
  410. type: Output
  411. }], accordions: [{
  412. type: ContentChildren,
  413. args: [AccordionComponent]
  414. }] } });
  415. class CardComponent {
  416. constructor() {
  417. this.header = '';
  418. this.subHeader = '';
  419. this.title = '';
  420. this.subTitle = '';
  421. this.avatar = '';
  422. this.image = '';
  423. this.imageThumbnail = '';
  424. this.withActions = false;
  425. }
  426. static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.2", ngImport: i0, type: CardComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
  427. static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "17.3.2", type: CardComponent, isStandalone: true, selector: "ct-card", inputs: { header: "header", subHeader: "subHeader", title: "title", subTitle: "subTitle", avatar: "avatar", image: "image", imageThumbnail: "imageThumbnail", withActions: "withActions" }, ngImport: i0, template: "<div class=\"flex w-full flex-col rounded-xl bg-surface text-on-surface dark:bg-surface-dark dark:text-on-surface-dark\">\n <div class=\"flex w-full flex-row items-stretch rounded-md\">\n <div class=\"flex w-full grow flex-row items-center gap-4 px-4 py-2\">\n <div class=\"items-center\">\n <ct-avatar [picture]=\"avatar\" [title]=\"title\" />\n </div>\n <div class=\"flex grow flex-col\">\n @if (header) {\n <span class=\"grow text-lg font-semibold\" [innerHTML]=\"header\"></span>\n }\n @if (subHeader) {\n <span class=\"grow text-sm\" [innerHTML]=\"subHeader\"></span>\n }\n </div>\n </div>\n <div class=\"flex flex-col justify-between rounded-r-xl\">\n @if (imageThumbnail) {\n <img class=\"flex max-w-24 rounded-tr-xl object-cover\" [src]=\"imageThumbnail\" [alt]=\"title\" />\n } @else {\n <ng-content select=\"[header-extra]\" />\n }\n </div>\n </div>\n @if (image) {\n <img class=\"size-full object-cover\" [src]=\"image\" [alt]=\"title\" />\n }\n @if (title || subTitle) {\n <div class=\"flex w-full flex-col px-4 py-2\">\n <div class=\"text-xl font-bold\" [innerHTML]=\"title\"></div>\n <div class=\"mb-2 text-base font-semibold\" [innerHTML]=\"subTitle\"></div>\n <div class=\"flex w-fit grow-0\"><ng-content select=\"[body]\" /></div>\n </div>\n }\n @if (withActions) {\n <div class=\"flex flex-row justify-end gap-2 px-4 py-2\">\n <ct-button text=\"test\" />\n <ct-button text=\"test\" type=\"secondary\" />\n </div>\n }\n</div>\n", dependencies: [{ kind: "component", type: AvatarComponent, selector: "ct-avatar", inputs: ["picture", "title"] }, { kind: "component", type: ButtonComponent, selector: "ct-button", inputs: ["text", "icon", "iconPosition", "fullSize", "size", "type", "variant"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
  428. }
  429. i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.2", ngImport: i0, type: CardComponent, decorators: [{
  430. type: Component,
  431. args: [{ selector: 'ct-card', standalone: true, imports: [AvatarComponent, ButtonComponent, SafeImagePipe], changeDetection: ChangeDetectionStrategy.OnPush, template: "<div class=\"flex w-full flex-col rounded-xl bg-surface text-on-surface dark:bg-surface-dark dark:text-on-surface-dark\">\n <div class=\"flex w-full flex-row items-stretch rounded-md\">\n <div class=\"flex w-full grow flex-row items-center gap-4 px-4 py-2\">\n <div class=\"items-center\">\n <ct-avatar [picture]=\"avatar\" [title]=\"title\" />\n </div>\n <div class=\"flex grow flex-col\">\n @if (header) {\n <span class=\"grow text-lg font-semibold\" [innerHTML]=\"header\"></span>\n }\n @if (subHeader) {\n <span class=\"grow text-sm\" [innerHTML]=\"subHeader\"></span>\n }\n </div>\n </div>\n <div class=\"flex flex-col justify-between rounded-r-xl\">\n @if (imageThumbnail) {\n <img class=\"flex max-w-24 rounded-tr-xl object-cover\" [src]=\"imageThumbnail\" [alt]=\"title\" />\n } @else {\n <ng-content select=\"[header-extra]\" />\n }\n </div>\n </div>\n @if (image) {\n <img class=\"size-full object-cover\" [src]=\"image\" [alt]=\"title\" />\n }\n @if (title || subTitle) {\n <div class=\"flex w-full flex-col px-4 py-2\">\n <div class=\"text-xl font-bold\" [innerHTML]=\"title\"></div>\n <div class=\"mb-2 text-base font-semibold\" [innerHTML]=\"subTitle\"></div>\n <div class=\"flex w-fit grow-0\"><ng-content select=\"[body]\" /></div>\n </div>\n }\n @if (withActions) {\n <div class=\"flex flex-row justify-end gap-2 px-4 py-2\">\n <ct-button text=\"test\" />\n <ct-button text=\"test\" type=\"secondary\" />\n </div>\n }\n</div>\n" }]
  432. }], propDecorators: { header: [{
  433. type: Input
  434. }], subHeader: [{
  435. type: Input
  436. }], title: [{
  437. type: Input
  438. }], subTitle: [{
  439. type: Input
  440. }], avatar: [{
  441. type: Input
  442. }], image: [{
  443. type: Input
  444. }], imageThumbnail: [{
  445. type: Input
  446. }], withActions: [{
  447. type: Input
  448. }] } });
  449. class DropdownDirective {
  450. constructor(
  451. //private element: ElementRef,
  452. renderer) {
  453. this.renderer = renderer;
  454. this.targetId = '';
  455. this.isVisible = false;
  456. }
  457. onBlur() {
  458. this.close(document.getElementById(this.targetId));
  459. }
  460. onClick() {
  461. this.toggle(document.getElementById(this.targetId));
  462. }
  463. toggle(element) {
  464. this.isVisible = !this.isVisible;
  465. this.renderer.addClass(element, this.isVisible ? 'block' : 'hidden');
  466. this.renderer.removeClass(element, this.isVisible ? 'hidden' : 'block');
  467. }
  468. close(element) {
  469. this.isVisible = false;
  470. this.renderer.addClass(element, 'hidden');
  471. this.renderer.removeClass(element, 'block');
  472. }
  473. static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.2", ngImport: i0, type: DropdownDirective, deps: [{ token: i0.Renderer2 }], target: i0.ɵɵFactoryTarget.Directive }); }
  474. static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "17.3.2", type: DropdownDirective, isStandalone: true, selector: "[ctDropdown]", inputs: { targetId: "targetId" }, host: { listeners: { "blur": "onBlur()", "focusout": "onBlur()", "click": "onClick()" } }, ngImport: i0 }); }
  475. }
  476. i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.2", ngImport: i0, type: DropdownDirective, decorators: [{
  477. type: Directive,
  478. args: [{
  479. selector: '[ctDropdown]',
  480. standalone: true,
  481. }]
  482. }], ctorParameters: () => [{ type: i0.Renderer2 }], propDecorators: { targetId: [{
  483. type: Input,
  484. args: [{ required: true }]
  485. }], onBlur: [{
  486. type: HostListener,
  487. args: ['blur']
  488. }, {
  489. type: HostListener,
  490. args: ['focusout']
  491. }], onClick: [{
  492. type: HostListener,
  493. args: ['click']
  494. }] } });
  495. class MenuComponent {
  496. constructor() {
  497. this.items = [];
  498. this.fullSize = true;
  499. this.direction = 'vertical';
  500. this.iconAlone = false;
  501. this.iconDirection = 'horizontal';
  502. }
  503. static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.2", ngImport: i0, type: MenuComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
  504. static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "17.3.2", type: MenuComponent, isStandalone: true, selector: "ct-menu", inputs: { items: "items", fullSize: "fullSize", direction: "direction", iconAlone: "iconAlone", iconDirection: "iconDirection" }, ngImport: i0, template: "<div\n class=\"z-10 flex flex-col rounded-md bg-surface p-2 text-on-surface shadow-lg dark:bg-surface-dark\"\n [class.w-fit]=\"!fullSize\"\n [class.w-full]=\"fullSize\">\n <ul\n class=\"flex justify-around\"\n [class.flex-col]=\"direction === 'vertical'\"\n [class.flex-row]=\"direction === 'horizontal'\">\n @for (item of items; track item) {\n <li>\n <!-- @if (item.subMenu && item.subMenu.length > 0) {\n <button ctDropdown [targetId]=\"'test'\">{{ item.text }}</button>\n <ct-menu class=\"absolute hidden\" [id]=\"'test'\" [items]=\"item.subMenu\" />\n } @else { -->\n <ct-menu-item\n [text]=\"item.text\"\n [link]=\"item.link\"\n [type]=\"item.type\"\n [icon]=\"item.icon!\"\n [iconAlone]=\"iconAlone\"\n [iconDirection]=\"iconDirection\" />\n <!-- } -->\n </li>\n }\n </ul>\n</div>\n", dependencies: [{ kind: "component", type: MenuItemComponent, selector: "ct-menu-item", inputs: ["text", "link", "type", "icon", "iconSize", "iconAlone", "iconDirection"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
  505. }
  506. i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.2", ngImport: i0, type: MenuComponent, decorators: [{
  507. type: Component,
  508. args: [{ selector: 'ct-menu', standalone: true, imports: [MenuItemComponent, DropdownDirective], changeDetection: ChangeDetectionStrategy.OnPush, template: "<div\n class=\"z-10 flex flex-col rounded-md bg-surface p-2 text-on-surface shadow-lg dark:bg-surface-dark\"\n [class.w-fit]=\"!fullSize\"\n [class.w-full]=\"fullSize\">\n <ul\n class=\"flex justify-around\"\n [class.flex-col]=\"direction === 'vertical'\"\n [class.flex-row]=\"direction === 'horizontal'\">\n @for (item of items; track item) {\n <li>\n <!-- @if (item.subMenu && item.subMenu.length > 0) {\n <button ctDropdown [targetId]=\"'test'\">{{ item.text }}</button>\n <ct-menu class=\"absolute hidden\" [id]=\"'test'\" [items]=\"item.subMenu\" />\n } @else { -->\n <ct-menu-item\n [text]=\"item.text\"\n [link]=\"item.link\"\n [type]=\"item.type\"\n [icon]=\"item.icon!\"\n [iconAlone]=\"iconAlone\"\n [iconDirection]=\"iconDirection\" />\n <!-- } -->\n </li>\n }\n </ul>\n</div>\n" }]
  509. }], propDecorators: { items: [{
  510. type: Input,
  511. args: [{ required: true }]
  512. }], fullSize: [{
  513. type: Input
  514. }], direction: [{
  515. type: Input
  516. }], iconAlone: [{
  517. type: Input
  518. }], iconDirection: [{
  519. type: Input
  520. }] } });
  521. class OptionComponent {
  522. constructor() {
  523. this.label = '';
  524. this.icon = '';
  525. }
  526. static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.2", ngImport: i0, type: OptionComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
  527. static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "17.3.2", type: OptionComponent, isStandalone: true, selector: "ct-option", inputs: { label: "label", icon: "icon" }, ngImport: i0, template: "<div\n class=\"flex cursor-pointer flex-row rounded-md px-4 py-2 text-sm hover:bg-surface/35 dark:hover:bg-surface-dark/35\">\n @if (icon) {\n <ct-icon [icon]=\"icon\" />\n }\n {{ label }}\n</div>\n", dependencies: [{ kind: "component", type: IconComponent, selector: "ct-icon", inputs: ["icon", "fill", "strokeWidth", "strokeColor", "size", "variant"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
  528. }
  529. i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.2", ngImport: i0, type: OptionComponent, decorators: [{
  530. type: Component,
  531. args: [{ selector: 'ct-option', standalone: true, imports: [IconComponent], changeDetection: ChangeDetectionStrategy.OnPush, template: "<div\n class=\"flex cursor-pointer flex-row rounded-md px-4 py-2 text-sm hover:bg-surface/35 dark:hover:bg-surface-dark/35\">\n @if (icon) {\n <ct-icon [icon]=\"icon\" />\n }\n {{ label }}\n</div>\n" }]
  532. }], propDecorators: { label: [{
  533. type: Input,
  534. args: [{ required: true }]
  535. }], icon: [{
  536. type: Input
  537. }] } });
  538. class LabelComponent {
  539. constructor() {
  540. this.text = '';
  541. this.type = TypeEnum.PRIMARY;
  542. this.formControlName = '';
  543. this.hasError = false;
  544. }
  545. static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.2", ngImport: i0, type: LabelComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
  546. static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "17.3.2", type: LabelComponent, isStandalone: true, selector: "ct-form-label", inputs: { text: "text", type: "type", formControlName: "formControlName", hasError: "hasError" }, ngImport: i0, template: "<label\n class=\"mb-1 flex font-medium\"\n [class.text-on-surface]=\"type === 'primary' && !hasError\"\n [class.text-secondary]=\"type === 'secondary'\"\n [class.text-warning-variation]=\"type === 'warning'\"\n [class.text-error-variation]=\"type === 'error' || hasError\"\n [class.text-success-variation]=\"type === 'success'\"\n [for]=\"formControlName\"\n >{{ text }}</label\n>\n", changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
  547. }
  548. i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.2", ngImport: i0, type: LabelComponent, decorators: [{
  549. type: Component,
  550. args: [{ selector: 'ct-form-label', standalone: true, imports: [], changeDetection: ChangeDetectionStrategy.OnPush, template: "<label\n class=\"mb-1 flex font-medium\"\n [class.text-on-surface]=\"type === 'primary' && !hasError\"\n [class.text-secondary]=\"type === 'secondary'\"\n [class.text-warning-variation]=\"type === 'warning'\"\n [class.text-error-variation]=\"type === 'error' || hasError\"\n [class.text-success-variation]=\"type === 'success'\"\n [for]=\"formControlName\"\n >{{ text }}</label\n>\n" }]
  551. }], propDecorators: { text: [{
  552. type: Input,
  553. args: [{ required: true }]
  554. }], type: [{
  555. type: Input
  556. }], formControlName: [{
  557. type: Input
  558. }], hasError: [{
  559. type: Input
  560. }] } });
  561. /**
  562. * Creates a value accessor provider for a form component.
  563. * @param component - The component that implements the NG_VALUE_ACCESSOR interface.
  564. * @returns An ExistingProvider object for the value accessor.
  565. */
  566. const provideValueAccessor = (component) => ({
  567. provide: NG_VALUE_ACCESSOR,
  568. useExisting: forwardRef(() => component),
  569. multi: true,
  570. });
  571. /**
  572. * Creates a control container provider using FormGroupDirective.
  573. * @returns An ExistingProvider object for the control container.
  574. */
  575. const provideControlContainer = () => ({
  576. provide: ControlContainer,
  577. useExisting: FormGroupDirective,
  578. });
  579. class FormGenericComponent {
  580. constructor(formGroupDirective) {
  581. this.formGroupDirective = formGroupDirective;
  582. this.onChange = () => { };
  583. this.onTouched = () => { };
  584. this.changeDetectorRef = inject(ChangeDetectorRef);
  585. }
  586. hasErrors(formControl) {
  587. return (formControl && !formControl.pristine && formControl.touched && !!formControl.errors);
  588. }
  589. get formControl() {
  590. return this.formGroupDirective.form.get(this.formControlName);
  591. }
  592. registerOnChange(fn) {
  593. this.onChange = fn;
  594. }
  595. registerOnTouched(fn) {
  596. this.onTouched = fn;
  597. }
  598. triggerChange(value) {
  599. this.onChange(value);
  600. }
  601. triggerTouched() {
  602. this.onTouched();
  603. }
  604. triggerChangeDetection() {
  605. this.changeDetectorRef.markForCheck();
  606. }
  607. }
  608. class FormErrorComponent {
  609. static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.2", ngImport: i0, type: FormErrorComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
  610. static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "17.3.2", type: FormErrorComponent, isStandalone: true, selector: "ct-form-error", inputs: { errors: "errors" }, ngImport: i0, template: "<div class=\"my-2 flex flex-col gap-1\">\n @for (error of errors | keyvalue; track error) {\n @if (error.key === 'required') {\n <ct-alert [text]=\"'Field is required'\" type=\"error\" [withIcon]=\"true\" variant=\"blank\" />\n } @else {\n <ct-alert [text]=\"error.key\" type=\"error\" [withIcon]=\"true\" variant=\"blank\" />\n }\n }\n</div>\n", dependencies: [{ kind: "component", type: AlertComponent, selector: "ct-alert", inputs: ["dismissable", "fullSize", "text", "type", "variant", "withIcon"], outputs: ["dismiss"] }, { kind: "pipe", type: KeyValuePipe, name: "keyvalue" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
  611. }
  612. i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.2", ngImport: i0, type: FormErrorComponent, decorators: [{
  613. type: Component,
  614. args: [{ selector: 'ct-form-error', standalone: true, imports: [AlertComponent, KeyValuePipe, JsonPipe], changeDetection: ChangeDetectionStrategy.OnPush, template: "<div class=\"my-2 flex flex-col gap-1\">\n @for (error of errors | keyvalue; track error) {\n @if (error.key === 'required') {\n <ct-alert [text]=\"'Field is required'\" type=\"error\" [withIcon]=\"true\" variant=\"blank\" />\n } @else {\n <ct-alert [text]=\"error.key\" type=\"error\" [withIcon]=\"true\" variant=\"blank\" />\n }\n }\n</div>\n" }]
  615. }], propDecorators: { errors: [{
  616. type: Input,
  617. args: [{ required: true }]
  618. }] } });
  619. class SelectComponent extends FormGenericComponent {
  620. constructor(formGroupDirective, destroyRef) {
  621. super(formGroupDirective);
  622. this.destroyRef = destroyRef;
  623. this.focusOut$ = new Subject();
  624. this.isOpen = false;
  625. this.option = '';
  626. this.option$ = signal('');
  627. this.placeholder = '';
  628. this.label = '';
  629. this.value = '';
  630. this.type = TypeEnum.PRIMARY;
  631. this.fullSize = true;
  632. this.shouldShowError = true;
  633. this.key = '';
  634. this.options = [];
  635. this.selected = new EventEmitter();
  636. }
  637. ngOnInit() {
  638. this.selectOption(this.value, false);
  639. this.focusOut$.pipe(takeUntilDestroyed(this.destroyRef), debounceTime(200)).subscribe(() => {
  640. this.triggerChangeDetection();
  641. this.close();
  642. });
  643. }
  644. toggle() {
  645. this.isOpen = !this.isOpen;
  646. if (!this.isOpen) {
  647. this.triggerTouched();
  648. }
  649. }
  650. close() {
  651. this.isOpen = false;
  652. this.triggerTouched();
  653. }
  654. selectOption(key, propagate = true) {
  655. const selectedOption = this.options.find(option => option.key === key);
  656. this.option = key === null ? this.placeholder : selectedOption?.label;
  657. if (propagate) {
  658. this.selected.emit(key);
  659. this.triggerChange(selectedOption?.key ?? null);
  660. this.close();
  661. }
  662. }
  663. writeValue(value) {
  664. this.triggerChangeDetection();
  665. this.selectOption(value, false);
  666. }
  667. static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.2", ngImport: i0, type: SelectComponent, deps: [{ token: i1$1.FormGroupDirective }, { token: i0.DestroyRef }], target: i0.ɵɵFactoryTarget.Component }); }
  668. static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "17.3.2", type: SelectComponent, isStandalone: true, selector: "ct-select", inputs: { formControlName: "formControlName", placeholder: "placeholder", label: "label", value: "value", type: "type", fullSize: "fullSize", shouldShowError: "shouldShowError", key: "key", options: "options" }, outputs: { selected: "selected" }, providers: [provideValueAccessor(forwardRef(() => SelectComponent))], viewQueries: [{ propertyName: "trigger", first: true, predicate: ["triggerElement"], descendants: true }, { propertyName: "panel", first: true, predicate: ["optionsPanel"], descendants: true }], usesInheritance: true, ngImport: i0, template: "<ct-form-label [text]=\"label\" [hasError]=\"hasErrors(formControl)\" />\n<div\n class=\"flex flex-row items-center justify-between gap-1.5 rounded-md border bg-surface-variant px-4 py-2 text-sm text-on-surface-variant dark:bg-surface-variant-dark dark:text-on-surface-variant-dark\"\n [class.border-error]=\"hasErrors(formControl)\"\n [class.border-neutral-300]=\"!hasErrors(formControl)\"\n [class.text-neutral-400]=\"option === placeholder\"\n [class.text-on-surface-variant]=\"option !== placeholder\"\n #triggerElement\n tabindex=\"0\"\n (focusout)=\"focusOut$.next($event)\"\n (click)=\"toggle()\">\n {{ option }}\n <ct-icon class=\"flex\" [size]=\"'sm'\" [icon]=\"isOpen ? 'chevron-up' : 'chevron-down'\" />\n</div>\n@if (isOpen) {\n <div class=\"relative\">\n <div\n #optionsPanel\n [class.w-full]=\"fullSize\"\n [class.w-fit]=\"!fullSize\"\n class=\"absolute top-1 z-10 flex flex-col rounded-md border border-neutral-400 bg-surface-variant text-on-surface-variant dark:bg-surface-variant-dark dark:text-on-surface-variant-dark\">\n <ct-option (click)=\"selectOption(null)\" [label]=\"placeholder\" />\n @for (option of options; track option) {\n <ct-option (click)=\"selectOption(option.key)\" [label]=\"option.label\" [icon]=\"option.icon!\" />\n }\n </div>\n </div>\n}\n@if (hasErrors(formControl)) {\n <ct-form-error [errors]=\"formControl.errors ?? {}\" />\n}\n", dependencies: [{ kind: "component", type: OptionComponent, selector: "ct-option", inputs: ["label", "icon"] }, { kind: "component", type: IconComponent, selector: "ct-icon", inputs: ["icon", "fill", "strokeWidth", "strokeColor", "size", "variant"] }, { kind: "component", type: LabelComponent, selector: "ct-form-label", inputs: ["text", "type", "formControlName", "hasError"] }, { kind: "component", type: FormErrorComponent, selector: "ct-form-error", inputs: ["errors"] }], viewProviders: [provideControlContainer()], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
  669. }
  670. i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.2", ngImport: i0, type: SelectComponent, decorators: [{
  671. type: Component,
  672. args: [{ selector: 'ct-select', standalone: true, imports: [OptionComponent, ButtonComponent, IconComponent, LabelComponent, AlertComponent, FormErrorComponent], providers: [provideValueAccessor(forwardRef(() => SelectComponent))], viewProviders: [provideControlContainer()], changeDetection: ChangeDetectionStrategy.OnPush, template: "<ct-form-label [text]=\"label\" [hasError]=\"hasErrors(formControl)\" />\n<div\n class=\"flex flex-row items-center justify-between gap-1.5 rounded-md border bg-surface-variant px-4 py-2 text-sm text-on-surface-variant dark:bg-surface-variant-dark dark:text-on-surface-variant-dark\"\n [class.border-error]=\"hasErrors(formControl)\"\n [class.border-neutral-300]=\"!hasErrors(formControl)\"\n [class.text-neutral-400]=\"option === placeholder\"\n [class.text-on-surface-variant]=\"option !== placeholder\"\n #triggerElement\n tabindex=\"0\"\n (focusout)=\"focusOut$.next($event)\"\n (click)=\"toggle()\">\n {{ option }}\n <ct-icon class=\"flex\" [size]=\"'sm'\" [icon]=\"isOpen ? 'chevron-up' : 'chevron-down'\" />\n</div>\n@if (isOpen) {\n <div class=\"relative\">\n <div\n #optionsPanel\n [class.w-full]=\"fullSize\"\n [class.w-fit]=\"!fullSize\"\n class=\"absolute top-1 z-10 flex flex-col rounded-md border border-neutral-400 bg-surface-variant text-on-surface-variant dark:bg-surface-variant-dark dark:text-on-surface-variant-dark\">\n <ct-option (click)=\"selectOption(null)\" [label]=\"placeholder\" />\n @for (option of options; track option) {\n <ct-option (click)=\"selectOption(option.key)\" [label]=\"option.label\" [icon]=\"option.icon!\" />\n }\n </div>\n </div>\n}\n@if (hasErrors(formControl)) {\n <ct-form-error [errors]=\"formControl.errors ?? {}\" />\n}\n" }]
  673. }], ctorParameters: () => [{ type: i1$1.FormGroupDirective }, { type: i0.DestroyRef }], propDecorators: { formControlName: [{
  674. type: Input
  675. }], placeholder: [{
  676. type: Input
  677. }], label: [{
  678. type: Input
  679. }], value: [{
  680. type: Input
  681. }], type: [{
  682. type: Input
  683. }], fullSize: [{
  684. type: Input
  685. }], shouldShowError: [{
  686. type: Input
  687. }], key: [{
  688. type: Input,
  689. args: [{ required: true }]
  690. }], options: [{
  691. type: Input,
  692. args: [{ required: true }]
  693. }], selected: [{
  694. type: Output
  695. }], trigger: [{
  696. type: ViewChild,
  697. args: ['triggerElement']
  698. }], panel: [{
  699. type: ViewChild,
  700. args: ['optionsPanel']
  701. }] } });
  702. class InputComponent extends FormGenericComponent {
  703. onFocusOut() {
  704. this.triggerTouched();
  705. }
  706. constructor(formGroupDirective) {
  707. super(formGroupDirective);
  708. this.key = '';
  709. this.label = '';
  710. this.placeholder = '';
  711. this.value = '';
  712. this.type = TypeEnum.PRIMARY;
  713. this.fullSize = true;
  714. this.typed = new EventEmitter();
  715. }
  716. input(event) {
  717. this.setValue(event.target.value);
  718. }
  719. setValue(value, propagate = true) {
  720. this.value = value;
  721. if (propagate) {
  722. this.triggerChange(value);
  723. this.typed.emit(value);
  724. }
  725. }
  726. writeValue(value) {
  727. this.triggerChangeDetection();
  728. this.setValue(value, false);
  729. }
  730. static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.2", ngImport: i0, type: InputComponent, deps: [{ token: i1$1.FormGroupDirective }], target: i0.ɵɵFactoryTarget.Component }); }
  731. static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "17.3.2", type: InputComponent, isStandalone: true, selector: "ct-input", inputs: { formControlName: "formControlName", key: "key", label: "label", placeholder: "placeholder", value: "value", type: "type", fullSize: "fullSize" }, outputs: { typed: "typed" }, host: { listeners: { "focusout": "onFocusOut()" } }, providers: [provideValueAccessor(forwardRef(() => InputComponent))], usesInheritance: true, ngImport: i0, template: "<ct-form-label [text]=\"label\" [hasError]=\"hasErrors(formControl)\" />\n<input\n tabindex=\"0\"\n class=\"rounded-md border bg-surface-variant px-4 py-2 text-sm text-on-surface-variant outline-none dark:bg-surface-variant-dark dark:text-on-surface-variant-dark\"\n [class.w-fit]=\"!fullSize\"\n [class.w-full]=\"fullSize\"\n [class.border-neutral-400]=\"formControl && (formControl.pristine || formControl.valid)\"\n [class.border-error]=\"hasErrors(formControl)\"\n [value]=\"value\"\n [placeholder]=\"placeholder\"\n (input)=\"input($event)\" />\n@if (hasErrors(formControl)) {\n <ct-form-error [errors]=\"formControl.errors ?? {}\" />\n}\n", dependencies: [{ kind: "component", type: LabelComponent, selector: "ct-form-label", inputs: ["text", "type", "formControlName", "hasError"] }, { kind: "component", type: FormErrorComponent, selector: "ct-form-error", inputs: ["errors"] }], viewProviders: [provideControlContainer()], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
  732. }
  733. i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.2", ngImport: i0, type: InputComponent, decorators: [{
  734. type: Component,
  735. args: [{ selector: 'ct-input', standalone: true, imports: [NgClass, LabelComponent, FormErrorComponent], providers: [provideValueAccessor(forwardRef(() => InputComponent))], viewProviders: [provideControlContainer()], changeDetection: ChangeDetectionStrategy.OnPush, template: "<ct-form-label [text]=\"label\" [hasError]=\"hasErrors(formControl)\" />\n<input\n tabindex=\"0\"\n class=\"rounded-md border bg-surface-variant px-4 py-2 text-sm text-on-surface-variant outline-none dark:bg-surface-variant-dark dark:text-on-surface-variant-dark\"\n [class.w-fit]=\"!fullSize\"\n [class.w-full]=\"fullSize\"\n [class.border-neutral-400]=\"formControl && (formControl.pristine || formControl.valid)\"\n [class.border-error]=\"hasErrors(formControl)\"\n [value]=\"value\"\n [placeholder]=\"placeholder\"\n (input)=\"input($event)\" />\n@if (hasErrors(formControl)) {\n <ct-form-error [errors]=\"formControl.errors ?? {}\" />\n}\n" }]
  736. }], ctorParameters: () => [{ type: i1$1.FormGroupDirective }], propDecorators: { formControlName: [{
  737. type: Input,
  738. args: [{ required: true }]
  739. }], key: [{
  740. type: Input,
  741. args: [{ required: true }]
  742. }], label: [{
  743. type: Input
  744. }], placeholder: [{
  745. type: Input
  746. }], value: [{
  747. type: Input
  748. }], type: [{
  749. type: Input
  750. }], fullSize: [{
  751. type: Input
  752. }], typed: [{
  753. type: Output
  754. }], onFocusOut: [{
  755. type: HostListener,
  756. args: ['focusout']
  757. }] } });
  758. class FormBase {
  759. constructor(options = {}) {
  760. this.value = options.value;
  761. this.key = options.key || undefined;
  762. this.label = options.label || '';
  763. this.placeholder = options.placeholder || '';
  764. this.required = !!options.required;
  765. this.controlType = options.controlType || '';
  766. this.options = options.options || [];
  767. }
  768. }
  769. class SelectFormBase extends FormBase {
  770. constructor() {
  771. super(...arguments);
  772. this.controlType = 'select';
  773. }
  774. }
  775. class InputFormBase extends FormBase {
  776. constructor() {
  777. super(...arguments);
  778. this.controlType = 'input';
  779. }
  780. }
  781. class ScreenSizeService {
  782. constructor() {
  783. this.destroyRef = inject(DestroyRef);
  784. this.screenSizeSubject = new BehaviorSubject(this.getScreenSize());
  785. this.screenSize$ = this.screenSizeSubject.asObservable();
  786. fromEvent(window, 'resize')
  787. .pipe(debounceTime$1(50), map(() => this.getScreenSize()), startWith(this.getScreenSize()), tap(() => console.log('test')), takeUntilDestroyed(this.destroyRef))
  788. .subscribe(this.screenSizeSubject);
  789. }
  790. getScreenSize() {
  791. const width = window.innerWidth;
  792. if (width < 640)
  793. return 'xs';
  794. if (width >= 640 && width < 768)
  795. return 'sm';
  796. if (width >= 768 && width < 1024)
  797. return 'md';
  798. if (width >= 1024 && width < 1280)
  799. return 'lg';
  800. if (width >= 1280 && width < 1536)
  801. return 'xl';
  802. return '2xl';
  803. }
  804. static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.2", ngImport: i0, type: ScreenSizeService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
  805. static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "17.3.2", ngImport: i0, type: ScreenSizeService, providedIn: 'root' }); }
  806. }
  807. i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.2", ngImport: i0, type: ScreenSizeService, decorators: [{
  808. type: Injectable,
  809. args: [{
  810. providedIn: 'root',
  811. }]
  812. }], ctorParameters: () => [] });
  813. /*
  814. * Public API Surface of circletone
  815. */
  816. // Atoms
  817. /**
  818. * Generated bundle index. Do not edit.
  819. */
  820. export { AccordionComponent, AccordionItemComponent, AccordionRegistryService, AlertComponent, AvatarComponent, ButtonComponent, CardComponent, DropdownDirective, FormBase, HeaderComponent, IconComponent, InputComponent, InputFormBase, MenuComponent, MenuItemComponent, SafeImagePipe, ScreenSizeService, SelectComponent, SelectFormBase, SizeEnum, TypeEnum, VariantEnum };
  821. //# sourceMappingURL=circletone.mjs.map