@star-ng/ui 0.0.0-stage → 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (217) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +148 -2
  3. package/fesm2022/star-ng-ui-accordion.mjs +376 -0
  4. package/fesm2022/star-ng-ui-accordion.mjs.map +1 -0
  5. package/fesm2022/star-ng-ui-autocomplete.mjs +782 -0
  6. package/fesm2022/star-ng-ui-autocomplete.mjs.map +1 -0
  7. package/fesm2022/star-ng-ui-avatar.mjs +154 -0
  8. package/fesm2022/star-ng-ui-avatar.mjs.map +1 -0
  9. package/fesm2022/star-ng-ui-badge.mjs +153 -0
  10. package/fesm2022/star-ng-ui-badge.mjs.map +1 -0
  11. package/fesm2022/star-ng-ui-breadcrumb.mjs +199 -0
  12. package/fesm2022/star-ng-ui-breadcrumb.mjs.map +1 -0
  13. package/fesm2022/star-ng-ui-button.mjs +282 -0
  14. package/fesm2022/star-ng-ui-button.mjs.map +1 -0
  15. package/fesm2022/star-ng-ui-card.mjs +112 -0
  16. package/fesm2022/star-ng-ui-card.mjs.map +1 -0
  17. package/fesm2022/star-ng-ui-chart.mjs +1904 -0
  18. package/fesm2022/star-ng-ui-chart.mjs.map +1 -0
  19. package/fesm2022/star-ng-ui-checkbox.mjs +345 -0
  20. package/fesm2022/star-ng-ui-checkbox.mjs.map +1 -0
  21. package/fesm2022/star-ng-ui-core.mjs +392 -0
  22. package/fesm2022/star-ng-ui-core.mjs.map +1 -0
  23. package/fesm2022/star-ng-ui-data-display.mjs +1556 -0
  24. package/fesm2022/star-ng-ui-data-display.mjs.map +1 -0
  25. package/fesm2022/star-ng-ui-date-picker.mjs +2786 -0
  26. package/fesm2022/star-ng-ui-date-picker.mjs.map +1 -0
  27. package/fesm2022/star-ng-ui-dialog.mjs +948 -0
  28. package/fesm2022/star-ng-ui-dialog.mjs.map +1 -0
  29. package/fesm2022/star-ng-ui-drawer.mjs +158 -0
  30. package/fesm2022/star-ng-ui-drawer.mjs.map +1 -0
  31. package/fesm2022/star-ng-ui-editor.mjs +416 -0
  32. package/fesm2022/star-ng-ui-editor.mjs.map +1 -0
  33. package/fesm2022/star-ng-ui-field.mjs +378 -0
  34. package/fesm2022/star-ng-ui-field.mjs.map +1 -0
  35. package/fesm2022/star-ng-ui-file-upload.mjs +762 -0
  36. package/fesm2022/star-ng-ui-file-upload.mjs.map +1 -0
  37. package/fesm2022/star-ng-ui-i18n-de.mjs +179 -0
  38. package/fesm2022/star-ng-ui-i18n-de.mjs.map +1 -0
  39. package/fesm2022/star-ng-ui-i18n-es.mjs +179 -0
  40. package/fesm2022/star-ng-ui-i18n-es.mjs.map +1 -0
  41. package/fesm2022/star-ng-ui-input-group.mjs +188 -0
  42. package/fesm2022/star-ng-ui-input-group.mjs.map +1 -0
  43. package/fesm2022/star-ng-ui-input-mask.mjs +434 -0
  44. package/fesm2022/star-ng-ui-input-mask.mjs.map +1 -0
  45. package/fesm2022/star-ng-ui-input-number.mjs +691 -0
  46. package/fesm2022/star-ng-ui-input-number.mjs.map +1 -0
  47. package/fesm2022/star-ng-ui-input-otp.mjs +343 -0
  48. package/fesm2022/star-ng-ui-input-otp.mjs.map +1 -0
  49. package/fesm2022/star-ng-ui-input-tags.mjs +616 -0
  50. package/fesm2022/star-ng-ui-input-tags.mjs.map +1 -0
  51. package/fesm2022/star-ng-ui-knob.mjs +514 -0
  52. package/fesm2022/star-ng-ui-knob.mjs.map +1 -0
  53. package/fesm2022/star-ng-ui-layout.mjs +608 -0
  54. package/fesm2022/star-ng-ui-layout.mjs.map +1 -0
  55. package/fesm2022/star-ng-ui-listbox.mjs +978 -0
  56. package/fesm2022/star-ng-ui-listbox.mjs.map +1 -0
  57. package/fesm2022/star-ng-ui-media.mjs +833 -0
  58. package/fesm2022/star-ng-ui-media.mjs.map +1 -0
  59. package/fesm2022/star-ng-ui-menu.mjs +1840 -0
  60. package/fesm2022/star-ng-ui-menu.mjs.map +1 -0
  61. package/fesm2022/star-ng-ui-message.mjs +191 -0
  62. package/fesm2022/star-ng-ui-message.mjs.map +1 -0
  63. package/fesm2022/star-ng-ui-paginator.mjs +387 -0
  64. package/fesm2022/star-ng-ui-paginator.mjs.map +1 -0
  65. package/fesm2022/star-ng-ui-panel.mjs +324 -0
  66. package/fesm2022/star-ng-ui-panel.mjs.map +1 -0
  67. package/fesm2022/star-ng-ui-password.mjs +517 -0
  68. package/fesm2022/star-ng-ui-password.mjs.map +1 -0
  69. package/fesm2022/star-ng-ui-popover.mjs +241 -0
  70. package/fesm2022/star-ng-ui-popover.mjs.map +1 -0
  71. package/fesm2022/star-ng-ui-progress-bar.mjs +183 -0
  72. package/fesm2022/star-ng-ui-progress-bar.mjs.map +1 -0
  73. package/fesm2022/star-ng-ui-radio.mjs +411 -0
  74. package/fesm2022/star-ng-ui-radio.mjs.map +1 -0
  75. package/fesm2022/star-ng-ui-rating.mjs +211 -0
  76. package/fesm2022/star-ng-ui-rating.mjs.map +1 -0
  77. package/fesm2022/star-ng-ui-select-button.mjs +613 -0
  78. package/fesm2022/star-ng-ui-select-button.mjs.map +1 -0
  79. package/fesm2022/star-ng-ui-select.mjs +2523 -0
  80. package/fesm2022/star-ng-ui-select.mjs.map +1 -0
  81. package/fesm2022/star-ng-ui-skeleton.mjs +160 -0
  82. package/fesm2022/star-ng-ui-skeleton.mjs.map +1 -0
  83. package/fesm2022/star-ng-ui-slider.mjs +552 -0
  84. package/fesm2022/star-ng-ui-slider.mjs.map +1 -0
  85. package/fesm2022/star-ng-ui-spinner.mjs +148 -0
  86. package/fesm2022/star-ng-ui-spinner.mjs.map +1 -0
  87. package/fesm2022/star-ng-ui-stepper.mjs +360 -0
  88. package/fesm2022/star-ng-ui-stepper.mjs.map +1 -0
  89. package/fesm2022/star-ng-ui-table.mjs +3477 -0
  90. package/fesm2022/star-ng-ui-table.mjs.map +1 -0
  91. package/fesm2022/star-ng-ui-tabs.mjs +464 -0
  92. package/fesm2022/star-ng-ui-tabs.mjs.map +1 -0
  93. package/fesm2022/star-ng-ui-tag.mjs +129 -0
  94. package/fesm2022/star-ng-ui-tag.mjs.map +1 -0
  95. package/fesm2022/star-ng-ui-theme-switch.mjs +105 -0
  96. package/fesm2022/star-ng-ui-theme-switch.mjs.map +1 -0
  97. package/fesm2022/star-ng-ui-theme.mjs +98 -0
  98. package/fesm2022/star-ng-ui-theme.mjs.map +1 -0
  99. package/fesm2022/star-ng-ui-toast.mjs +298 -0
  100. package/fesm2022/star-ng-ui-toast.mjs.map +1 -0
  101. package/fesm2022/star-ng-ui-toggle-switch.mjs +316 -0
  102. package/fesm2022/star-ng-ui-toggle-switch.mjs.map +1 -0
  103. package/fesm2022/star-ng-ui-tooltip.mjs +297 -0
  104. package/fesm2022/star-ng-ui-tooltip.mjs.map +1 -0
  105. package/fesm2022/star-ng-ui-transloco.mjs +40 -0
  106. package/fesm2022/star-ng-ui-transloco.mjs.map +1 -0
  107. package/fesm2022/star-ng-ui-tree.mjs +1446 -0
  108. package/fesm2022/star-ng-ui-tree.mjs.map +1 -0
  109. package/fesm2022/star-ng-ui-utility.mjs +2134 -0
  110. package/fesm2022/star-ng-ui-utility.mjs.map +1 -0
  111. package/fesm2022/star-ng-ui.mjs +51 -0
  112. package/package.json +281 -3
  113. package/styles/_base.scss +70 -0
  114. package/styles/_shared.scss +2 -0
  115. package/styles/_tokens.scss +190 -0
  116. package/styles/controls/_accordion.scss +75 -0
  117. package/styles/controls/_autocomplete.scss +44 -0
  118. package/styles/controls/_avatar.scss +39 -0
  119. package/styles/controls/_breadcrumb.scss +45 -0
  120. package/styles/controls/_button.scss +137 -0
  121. package/styles/controls/_card.scss +38 -0
  122. package/styles/controls/_chart.scss +214 -0
  123. package/styles/controls/_chip.scss +51 -0
  124. package/styles/controls/_choice.scss +153 -0
  125. package/styles/controls/_data-display.scss +118 -0
  126. package/styles/controls/_date-picker.scss +300 -0
  127. package/styles/controls/_dialog.scss +123 -0
  128. package/styles/controls/_drawer.scss +118 -0
  129. package/styles/controls/_editor.scss +74 -0
  130. package/styles/controls/_field.scss +92 -0
  131. package/styles/controls/_file-upload.scss +136 -0
  132. package/styles/controls/_input-group.scss +104 -0
  133. package/styles/controls/_input-mask.scss +46 -0
  134. package/styles/controls/_input-number.scss +125 -0
  135. package/styles/controls/_knob.scss +76 -0
  136. package/styles/controls/_layout.scss +182 -0
  137. package/styles/controls/_listbox.scss +38 -0
  138. package/styles/controls/_media.scss +222 -0
  139. package/styles/controls/_menu.scss +254 -0
  140. package/styles/controls/_message.scss +48 -0
  141. package/styles/controls/_org-chart.scss +128 -0
  142. package/styles/controls/_paginator.scss +59 -0
  143. package/styles/controls/_panel.scss +83 -0
  144. package/styles/controls/_popover.scss +40 -0
  145. package/styles/controls/_progress-bar.scss +74 -0
  146. package/styles/controls/_select-button.scss +61 -0
  147. package/styles/controls/_select.scss +216 -0
  148. package/styles/controls/_skeleton.scss +43 -0
  149. package/styles/controls/_slider.scss +163 -0
  150. package/styles/controls/_spinner.scss +34 -0
  151. package/styles/controls/_stepper.scss +109 -0
  152. package/styles/controls/_table.scss +523 -0
  153. package/styles/controls/_tabs.scss +93 -0
  154. package/styles/controls/_tag.scss +84 -0
  155. package/styles/controls/_toast.scss +141 -0
  156. package/styles/controls/_tooltip.scss +14 -0
  157. package/styles/controls/_tree.scss +113 -0
  158. package/styles/controls/_utility.scss +654 -0
  159. package/styles/star-ng.css +5803 -0
  160. package/styles/star-ng.min.css +1 -0
  161. package/styles/star-ng.scss +50 -0
  162. package/theme/star-theme-first-paint.js +1 -0
  163. package/types/star-ng-ui-accordion.d.ts +82 -0
  164. package/types/star-ng-ui-autocomplete.d.ts +171 -0
  165. package/types/star-ng-ui-avatar.d.ts +43 -0
  166. package/types/star-ng-ui-badge.d.ts +46 -0
  167. package/types/star-ng-ui-breadcrumb.d.ts +39 -0
  168. package/types/star-ng-ui-button.d.ts +79 -0
  169. package/types/star-ng-ui-card.d.ts +29 -0
  170. package/types/star-ng-ui-chart.d.ts +337 -0
  171. package/types/star-ng-ui-checkbox.d.ts +92 -0
  172. package/types/star-ng-ui-core.d.ts +310 -0
  173. package/types/star-ng-ui-data-display.d.ts +339 -0
  174. package/types/star-ng-ui-date-picker.d.ts +701 -0
  175. package/types/star-ng-ui-dialog.d.ts +254 -0
  176. package/types/star-ng-ui-drawer.d.ts +29 -0
  177. package/types/star-ng-ui-editor.d.ts +96 -0
  178. package/types/star-ng-ui-field.d.ts +146 -0
  179. package/types/star-ng-ui-file-upload.d.ts +192 -0
  180. package/types/star-ng-ui-i18n-de.d.ts +7 -0
  181. package/types/star-ng-ui-i18n-es.d.ts +7 -0
  182. package/types/star-ng-ui-input-group.d.ts +58 -0
  183. package/types/star-ng-ui-input-mask.d.ts +126 -0
  184. package/types/star-ng-ui-input-number.d.ts +193 -0
  185. package/types/star-ng-ui-input-otp.d.ts +86 -0
  186. package/types/star-ng-ui-input-tags.d.ts +159 -0
  187. package/types/star-ng-ui-knob.d.ts +121 -0
  188. package/types/star-ng-ui-layout.d.ts +154 -0
  189. package/types/star-ng-ui-listbox.d.ts +197 -0
  190. package/types/star-ng-ui-media.d.ts +161 -0
  191. package/types/star-ng-ui-menu.d.ts +332 -0
  192. package/types/star-ng-ui-message.d.ts +52 -0
  193. package/types/star-ng-ui-paginator.d.ts +85 -0
  194. package/types/star-ng-ui-panel.d.ts +65 -0
  195. package/types/star-ng-ui-password.d.ts +129 -0
  196. package/types/star-ng-ui-popover.d.ts +57 -0
  197. package/types/star-ng-ui-progress-bar.d.ts +49 -0
  198. package/types/star-ng-ui-radio.d.ts +116 -0
  199. package/types/star-ng-ui-rating.d.ts +52 -0
  200. package/types/star-ng-ui-select-button.d.ts +169 -0
  201. package/types/star-ng-ui-select.d.ts +540 -0
  202. package/types/star-ng-ui-skeleton.d.ts +47 -0
  203. package/types/star-ng-ui-slider.d.ts +145 -0
  204. package/types/star-ng-ui-spinner.d.ts +29 -0
  205. package/types/star-ng-ui-stepper.d.ts +89 -0
  206. package/types/star-ng-ui-table.d.ts +829 -0
  207. package/types/star-ng-ui-tabs.d.ts +109 -0
  208. package/types/star-ng-ui-tag.d.ts +35 -0
  209. package/types/star-ng-ui-theme-switch.d.ts +36 -0
  210. package/types/star-ng-ui-theme.d.ts +95 -0
  211. package/types/star-ng-ui-toast.d.ts +84 -0
  212. package/types/star-ng-ui-toggle-switch.d.ts +81 -0
  213. package/types/star-ng-ui-tooltip.d.ts +66 -0
  214. package/types/star-ng-ui-transloco.d.ts +14 -0
  215. package/types/star-ng-ui-tree.d.ts +310 -0
  216. package/types/star-ng-ui-utility.d.ts +533 -0
  217. package/types/star-ng-ui.d.ts +51 -0
@@ -0,0 +1,105 @@
1
+ import * as i0 from "@angular/core";
2
+ import { ChangeDetectionStrategy, Component, computed, inject } from "@angular/core";
3
+ import { STAR_UI_TEXT } from "@star-ng/ui/core";
4
+ import { StarThemeService } from "@star-ng/ui/theme";
5
+ import { StarSpeedDial } from "@star-ng/ui/utility";
6
+ const MODES = [
7
+ {
8
+ mode: "system",
9
+ icon: "ph-bold ph-monitor"
10
+ },
11
+ {
12
+ mode: "light",
13
+ icon: "ph-bold ph-sun"
14
+ },
15
+ {
16
+ mode: "dark",
17
+ icon: "ph-bold ph-moon"
18
+ }
19
+ ];
20
+ var StarThemeSwitch = class StarThemeSwitch {
21
+ theme = inject(StarThemeService);
22
+ text = inject(STAR_UI_TEXT);
23
+ activeIndex = computed(() => MODES.findIndex((item) => item.mode === this.theme.mode()), ...ngDevMode ? [{ debugName: "activeIndex" }] : /* istanbul ignore next */ []);
24
+ current = computed(() => MODES[this.activeIndex()] ?? MODES[0], ...ngDevMode ? [{ debugName: "current" }] : /* istanbul ignore next */ []);
25
+ modeLabel(mode) {
26
+ return mode === "system" ? this.text.themeSystem : mode === "light" ? this.text.themeLight : this.text.themeDark;
27
+ }
28
+ items = computed(() => MODES.map(({ mode, icon }) => ({
29
+ label: this.modeLabel(mode),
30
+ icon,
31
+ command: () => this.theme.setMode(mode)
32
+ })), ...ngDevMode ? [{ debugName: "items" }] : /* istanbul ignore next */ []);
33
+ label = computed(() => `${this.text.theme}: ${this.modeLabel(this.current().mode)}`, ...ngDevMode ? [{ debugName: "label" }] : /* istanbul ignore next */ []);
34
+ static ɵfac = i0.ɵɵngDeclareFactory({
35
+ minVersion: "12.0.0",
36
+ version: "22.2.6",
37
+ ngImport: i0,
38
+ type: StarThemeSwitch,
39
+ deps: [],
40
+ target: i0.ɵɵFactoryTarget.Component
41
+ });
42
+ static ɵcmp = i0.ɵɵngDeclareComponent({
43
+ minVersion: "14.0.0",
44
+ version: "22.2.6",
45
+ type: StarThemeSwitch,
46
+ isStandalone: true,
47
+ selector: "star-theme-switch",
48
+ host: { classAttribute: "star-theme-switch" },
49
+ ngImport: i0,
50
+ template: `
51
+ <star-speed-dial
52
+ size="sm"
53
+ direction="down"
54
+ [icon]="current().icon"
55
+ [items]="items()"
56
+ [activeIndex]="activeIndex()"
57
+ [ariaLabel]="label()"
58
+ />
59
+ `,
60
+ isInline: true,
61
+ dependencies: [{
62
+ kind: "component",
63
+ type: StarSpeedDial,
64
+ selector: "star-speed-dial",
65
+ inputs: [
66
+ "items",
67
+ "direction",
68
+ "ariaLabel",
69
+ "icon",
70
+ "size",
71
+ "activeIndex"
72
+ ],
73
+ outputs: ["itemClick"]
74
+ }],
75
+ changeDetection: i0.ChangeDetectionStrategy.OnPush
76
+ });
77
+ };
78
+ i0.ɵɵngDeclareClassMetadata({
79
+ minVersion: "12.0.0",
80
+ version: "22.2.6",
81
+ ngImport: i0,
82
+ type: StarThemeSwitch,
83
+ decorators: [{
84
+ type: Component,
85
+ args: [{
86
+ selector: "star-theme-switch",
87
+ imports: [StarSpeedDial],
88
+ changeDetection: ChangeDetectionStrategy.OnPush,
89
+ host: { class: "star-theme-switch" },
90
+ template: `
91
+ <star-speed-dial
92
+ size="sm"
93
+ direction="down"
94
+ [icon]="current().icon"
95
+ [items]="items()"
96
+ [activeIndex]="activeIndex()"
97
+ [ariaLabel]="label()"
98
+ />
99
+ `
100
+ }]
101
+ }]
102
+ });
103
+ export { StarThemeSwitch };
104
+
105
+ //# sourceMappingURL=star-ng-ui-theme-switch.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"star-ng-ui-theme-switch.mjs","names":[],"sources":["../../../projects/star-ng/theme-switch/theme-switch.ts"],"sourcesContent":["import { ChangeDetectionStrategy, Component, computed, inject } from '@angular/core';\nimport { STAR_UI_TEXT } from '@star-ng/ui/core';\nimport { StarMenuItem } from '@star-ng/ui/menu';\nimport { StarThemeMode, StarThemeService } from '@star-ng/ui/theme';\nimport { StarSpeedDial } from '@star-ng/ui/utility';\n\nconst MODES: readonly { readonly mode: StarThemeMode; readonly icon: string }[] = [\n { mode: 'system', icon: 'ph-bold ph-monitor' },\n { mode: 'light', icon: 'ph-bold ph-sun' },\n { mode: 'dark', icon: 'ph-bold ph-moon' },\n];\n\n/**\n * Theme switch: a small speed dial with System, Light and Dark. The button shows the icon of\n * the current choice; `StarThemeService` applies and remembers it. The texts come from\n * `STAR_UI_TEXT` (`theme`, `themeSystem`, `themeLight`, `themeDark`).\n *\n * The control is not positioned: the host places it. For a fixed corner:\n *\n * ```css\n * star-theme-switch {\n * position: fixed;\n * top: var(--star-space-3);\n * inset-inline-end: var(--star-space-4);\n * z-index: 40;\n * }\n * ```\n *\n * `<star-theme-switch />`\n */\n@Component({\n selector: 'star-theme-switch',\n imports: [StarSpeedDial],\n changeDetection: ChangeDetectionStrategy.OnPush,\n host: { class: 'star-theme-switch' },\n template: `\n <star-speed-dial\n size=\"sm\"\n direction=\"down\"\n [icon]=\"current().icon\"\n [items]=\"items()\"\n [activeIndex]=\"activeIndex()\"\n [ariaLabel]=\"label()\"\n />\n `,\n})\nexport class StarThemeSwitch {\n private readonly theme = inject(StarThemeService);\n private readonly text = inject(STAR_UI_TEXT);\n\n protected readonly activeIndex = computed(() =>\n MODES.findIndex((item) => item.mode === this.theme.mode()),\n );\n protected readonly current = computed(() => MODES[this.activeIndex()] ?? MODES[0]);\n\n private modeLabel(mode: StarThemeMode): string {\n return mode === 'system'\n ? this.text.themeSystem\n : mode === 'light'\n ? this.text.themeLight\n : this.text.themeDark;\n }\n\n protected readonly items = computed<readonly StarMenuItem[]>(() =>\n MODES.map(({ mode, icon }) => ({\n label: this.modeLabel(mode),\n icon,\n command: () => this.theme.setMode(mode),\n })),\n );\n\n /** Accessible name of the button, for example \"Theme: Dark\". */\n protected readonly label = computed(\n () => `${this.text.theme}: ${this.modeLabel(this.current().mode)}`,\n );\n}\n"],"mappings":";;;;;AAMA,MAAM,QAA4E;CAChF;EAAE,MAAM;EAAU,MAAM;CAAoB;CAC5C;EAAE,MAAM;EAAS,MAAM;CAAgB;CACvC;EAAE,MAAM;EAAQ,MAAM;CAAiB;AACxC;AAoCD,IAAa,kBAAb,MAAa,gBAAe;CACT,QAAQ,OAAO,gBAAgB;CAC/B,OAAO,OAAO,YAAY;CAExB,cAAc,eAC/B,MAAM,WAAW,SAAS,KAAK,SAAS,KAAK,MAAM,KAAI,CAAE,GAC1D,GAAA,YAAA,CAAA,EAAA,WAAA,cAAA,CAAA,+BAAA,CAAA,CAAA;CACkB,UAAU,eAAe,MAAM,KAAK,YAAW,MAAO,MAAM,IAAG,GAAA,YAAA,CAAA,EAAA,WAAA,UAAA,CAAA,+BAAA,CAAA,CAAA;CAE1E,UAAU,MAAmB;EACnC,OAAO,SAAS,WACZ,KAAK,KAAK,cACV,SAAS,UACP,KAAK,KAAK,aACV,KAAK,KAAK;CAClB;CAEmB,QAAQ,eACzB,MAAM,KAAK,EAAE,MAAM,YAAY;EAC7B,OAAO,KAAK,UAAU,IAAI;EAC1B;EACA,eAAe,KAAK,MAAM,QAAQ,IAAI;CACvC,EAAC,GACH,GAAA,YAAA,CAAA,EAAA,WAAA,QAAA,CAAA,+BAAA,CAAA,CAAA;CAGkB,QAAQ,eACnB,GAAG,KAAK,KAAK,MAAK,IAAK,KAAK,UAAU,KAAK,QAAO,CAAE,CAAC,IAAI,KAChE,GAAA,YAAA,CAAA,EAAA,WAAA,QAAA,CAAA,+BAAA,CAAA,CAAA;CA5BU,OAAA,OAAA,GAAA,mBAAA;EAAA,YAAA;EAAA,SAAA;EAAA,UAAA;EAAA,MAAA;EAAe,MAAA,CAAA;EAAA,QAAA,GAAA,gBAAA;CAAA,CAAA;CAAf,OAAA,OAAA,GAAA,qBAAA;EAAA,YAAA;EAAA,SAAA;EAAA,MAAA;EAAe,cAAA;EAAA,UAAA;EAAA,MAAA,EAAA,gBAAA,oBAAA;EAAA,UAAA;EAAA,UAXhB;;;;;;;;;;EAST,UAAA;EAAA,cAAA,CAAA;GAAA,MAAA;GAAA,MAZS;GAAa,UAAA;GAAA,QAAA;IAAA;IAAA;IAAA;IAAA;IAAA;IAAA;GAAA;GAAA,SAAA,CAAA,WAAA;EAAA,CAAA;EAAA,iBAAA,GAAA,wBAAA;CAAA,CAAA;;AAcZ,GAAA,yBAAA;CAAA,YAAA;CAAA,SAAA;CAAA,UAAA;CAAA,MAAA;CAAe,YAAA,CAAA;EAhB3B,MAAA;EAAU,MAAA,CAAA;GACT,UAAU;GACV,SAAS,CAAC,aAAa;GACvB,iBAAiB,wBAAwB;GACzC,MAAM,EAAE,OAAO,oBAAmB;GAClC,UAAU;;;;;;;;;;EAUX,CAAA"}
@@ -0,0 +1,98 @@
1
+ import { DOCUMENT } from "@angular/common";
2
+ import * as i0 from "@angular/core";
3
+ import { Injectable, InjectionToken, computed, effect, inject, signal } from "@angular/core";
4
+ const STAR_THEME_DEFAULT_STORAGE_KEY = "star-theme";
5
+ function firstPaintSource(keyExpression) {
6
+ return `(function(){var m='system';try{m=localStorage.getItem(${keyExpression})||'system'}catch(e){}var d=m==='dark'||(m!=='light'&&window.matchMedia&&window.matchMedia('(prefers-color-scheme: dark)').matches);document.documentElement.setAttribute('data-theme',d?'dark':'light')})();`;
7
+ }
8
+ function scriptLiteral(value) {
9
+ return JSON.stringify(value).replace(/</g, String.raw`\u003c`);
10
+ }
11
+ function starThemeFirstPaintScript(storageKey = STAR_THEME_DEFAULT_STORAGE_KEY) {
12
+ return firstPaintSource(scriptLiteral(storageKey));
13
+ }
14
+ function starThemeFirstPaintFileScript() {
15
+ return firstPaintSource(`document.currentScript&&document.currentScript.getAttribute('data-storage-key')||${scriptLiteral(STAR_THEME_DEFAULT_STORAGE_KEY)}`);
16
+ }
17
+ const STAR_THEME_FIRST_PAINT_HASH = "'sha256-mHrWsD/vOGmnKvtGE+U7/5fQm439nYWV30PcQ/ez708='";
18
+ async function starThemeFirstPaintHash(storageKey = STAR_THEME_DEFAULT_STORAGE_KEY) {
19
+ const bytes = new TextEncoder().encode(starThemeFirstPaintScript(storageKey));
20
+ const digest = new Uint8Array(await crypto.subtle.digest("SHA-256", bytes));
21
+ let binary = "";
22
+ for (const byte of digest) binary += String.fromCharCode(byte);
23
+ return `'sha256-${btoa(binary)}'`;
24
+ }
25
+ const NONCE = /^[A-Za-z0-9+/_-]+={0,2}$/;
26
+ function starThemeFirstPaintElement(nonce, storageKey = STAR_THEME_DEFAULT_STORAGE_KEY) {
27
+ if (typeof nonce !== "string" || !NONCE.test(nonce)) throw new Error("starThemeFirstPaintElement: the nonce must be a base64 or base64url value.");
28
+ return `<script nonce="${nonce}">${starThemeFirstPaintScript(storageKey)}<\/script>`;
29
+ }
30
+ const STAR_THEME_STORAGE_KEY = new InjectionToken("STAR_THEME_STORAGE_KEY", {
31
+ providedIn: "root",
32
+ factory: () => STAR_THEME_DEFAULT_STORAGE_KEY
33
+ });
34
+ const MODES = [
35
+ "system",
36
+ "light",
37
+ "dark"
38
+ ];
39
+ var StarThemeService = class StarThemeService {
40
+ document = inject(DOCUMENT);
41
+ storageKey = inject(STAR_THEME_STORAGE_KEY);
42
+ view = this.document.defaultView;
43
+ systemQuery = this.view?.matchMedia?.("(prefers-color-scheme: dark)") ?? null;
44
+ systemDark = signal(this.systemQuery?.matches ?? false, ...ngDevMode ? [{ debugName: "systemDark" }] : /* istanbul ignore next */ []);
45
+ mode = signal(this.stored(), ...ngDevMode ? [{ debugName: "mode" }] : /* istanbul ignore next */ []);
46
+ theme = computed(() => {
47
+ const mode = this.mode();
48
+ if (mode === "system") return this.systemDark() ? "dark" : "light";
49
+ return mode;
50
+ }, ...ngDevMode ? [{ debugName: "theme" }] : /* istanbul ignore next */ []);
51
+ constructor() {
52
+ this.systemQuery?.addEventListener?.("change", (event) => this.systemDark.set(event.matches));
53
+ effect(() => this.document.documentElement.setAttribute("data-theme", this.theme()));
54
+ }
55
+ setMode(mode) {
56
+ this.mode.set(mode);
57
+ try {
58
+ this.view?.localStorage.setItem(this.storageKey, mode);
59
+ } catch {}
60
+ }
61
+ stored() {
62
+ try {
63
+ const value = this.view?.localStorage.getItem(this.storageKey);
64
+ return MODES.includes(value) ? value : "system";
65
+ } catch {
66
+ return "system";
67
+ }
68
+ }
69
+ static ɵfac = i0.ɵɵngDeclareFactory({
70
+ minVersion: "12.0.0",
71
+ version: "22.2.6",
72
+ ngImport: i0,
73
+ type: StarThemeService,
74
+ deps: [],
75
+ target: i0.ɵɵFactoryTarget.Injectable
76
+ });
77
+ static ɵprov = i0.ɵɵngDeclareInjectable({
78
+ minVersion: "12.0.0",
79
+ version: "22.2.6",
80
+ ngImport: i0,
81
+ type: StarThemeService,
82
+ providedIn: "root"
83
+ });
84
+ };
85
+ i0.ɵɵngDeclareClassMetadata({
86
+ minVersion: "12.0.0",
87
+ version: "22.2.6",
88
+ ngImport: i0,
89
+ type: StarThemeService,
90
+ decorators: [{
91
+ type: Injectable,
92
+ args: [{ providedIn: "root" }]
93
+ }],
94
+ ctorParameters: () => []
95
+ });
96
+ export { STAR_THEME_DEFAULT_STORAGE_KEY, STAR_THEME_FIRST_PAINT_HASH, STAR_THEME_STORAGE_KEY, StarThemeService, starThemeFirstPaintElement, starThemeFirstPaintFileScript, starThemeFirstPaintHash, starThemeFirstPaintScript };
97
+
98
+ //# sourceMappingURL=star-ng-ui-theme.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"star-ng-ui-theme.mjs","names":[],"sources":["../../../projects/star-ng/theme/theme-key.ts","../../../projects/star-ng/theme/first-paint.ts","../../../projects/star-ng/theme/theme.service.ts"],"sourcesContent":["/** Default `localStorage` key of the saved theme choice. */\nexport const STAR_THEME_DEFAULT_STORAGE_KEY = 'star-theme';\n","import { STAR_THEME_DEFAULT_STORAGE_KEY } from './theme-key';\n\n/**\n * Builds the script text. `keyExpression` is JavaScript source that gives the storage key.\n * The inline form uses a string literal; the file form reads an attribute of its own element.\n */\nfunction firstPaintSource(keyExpression: string): string {\n return (\n `(function(){var m='system';try{m=localStorage.getItem(${keyExpression})||'system'}catch(e){}` +\n `var d=m==='dark'||(m!=='light'&&window.matchMedia&&` +\n `window.matchMedia('(prefers-color-scheme: dark)').matches);` +\n `document.documentElement.setAttribute('data-theme',d?'dark':'light')})();`\n );\n}\n\n/** A string literal that is safe inside an HTML `<script>` element (it escapes every `<`). */\nfunction scriptLiteral(value: string): string {\n return JSON.stringify(value).replace(/</g, String.raw`\\u003c`);\n}\n\n/**\n * Source of the first-paint theme script. It sets `data-theme` on `<html>` before the browser\n * paints, so a dark-theme user does not see a light frame while the application starts.\n *\n * The rule is the same as in `StarThemeService`: the saved choice (`system`, `light` or\n * `dark`), else the system setting.\n *\n * A strict Content Security Policy (`script-src 'self'`, no `'unsafe-inline'`) blocks an inline\n * script. There are three ways that work with it. See the \"Content Security Policy\" section of\n * the \"Dark mode\" guide:\n *\n * 1. the static file `@star-ng/ui/theme/star-theme-first-paint.js` (see\n * `starThemeFirstPaintFileScript`), loaded with `<script src>`;\n * 2. the hash of this text in the policy (`STAR_THEME_FIRST_PAINT_HASH`,\n * `starThemeFirstPaintHash`);\n * 3. a nonce (`starThemeFirstPaintElement`).\n *\n * ```ts\n * // For example in a build script or a server-side template:\n * const html = `<script>${starThemeFirstPaintScript()}</script>`;\n * ```\n *\n * @param storageKey The `localStorage` key. Use the value of `STAR_THEME_STORAGE_KEY`.\n */\nexport function starThemeFirstPaintScript(storageKey = STAR_THEME_DEFAULT_STORAGE_KEY): string {\n return firstPaintSource(scriptLiteral(storageKey));\n}\n\n/**\n * Text of the static file `@star-ng/ui/theme/star-theme-first-paint.js`. It is the same script as\n * `starThemeFirstPaintScript()`, but the storage key comes from the `data-storage-key`\n * attribute of its own `<script>` element (default `'star-theme'`), so a custom key needs no\n * inline code:\n *\n * ```html\n * <script src=\"star-theme-first-paint.js\" data-storage-key=\"my-app-theme\"></script>\n * ```\n *\n * A unit test keeps the file and this function identical.\n */\nexport function starThemeFirstPaintFileScript(): string {\n return firstPaintSource(\n `document.currentScript&&document.currentScript.getAttribute('data-storage-key')||${scriptLiteral(\n STAR_THEME_DEFAULT_STORAGE_KEY,\n )}`,\n );\n}\n\n/**\n * CSP hash source of `starThemeFirstPaintScript()` with the default storage key. Put it in\n * `script-src`, and write the script between the tags with no extra character: no space, no\n * line break. A unit test recomputes it, so it cannot be stale.\n */\nexport const STAR_THEME_FIRST_PAINT_HASH = \"'sha256-mHrWsD/vOGmnKvtGE+U7/5fQm439nYWV30PcQ/ez708='\";\n\n/**\n * Computes the CSP hash source (`'sha256-...'`, with the quotes) of the exact text of\n * `starThemeFirstPaintScript(storageKey)`. The browser hashes the UTF-8 bytes of the text\n * between `<script>` and `</script>`. Use it for a custom storage key (needs Web Crypto, so a\n * secure context or a current Node.js version).\n */\nexport async function starThemeFirstPaintHash(\n storageKey = STAR_THEME_DEFAULT_STORAGE_KEY,\n): Promise<string> {\n const bytes = new TextEncoder().encode(starThemeFirstPaintScript(storageKey));\n const digest = new Uint8Array(await crypto.subtle.digest('SHA-256', bytes));\n let binary = '';\n for (const byte of digest) binary += String.fromCharCode(byte);\n return `'sha256-${btoa(binary)}'`;\n}\n\n/** A nonce is base64 or base64url text (`A-Z a-z 0-9 + / - _`, at most two `=` at the end). */\nconst NONCE = /^[A-Za-z0-9+/_-]+={0,2}$/;\n\n/**\n * The full `<script nonce=\"...\">...</script>` element text of the first-paint script, for a\n * server-rendered page. Add `'nonce-<same value>'` to `script-src`. Use a new random nonce\n * (at least 128 bits) for each response.\n *\n * @throws Error when the nonce is not a valid base64 or base64url value. The check keeps\n * markup out of the attribute.\n */\nexport function starThemeFirstPaintElement(\n nonce: string,\n storageKey = STAR_THEME_DEFAULT_STORAGE_KEY,\n): string {\n if (typeof nonce !== 'string' || !NONCE.test(nonce)) {\n throw new Error('starThemeFirstPaintElement: the nonce must be a base64 or base64url value.');\n }\n return `<script nonce=\"${nonce}\">${starThemeFirstPaintScript(storageKey)}</script>`;\n}\n","import { DOCUMENT } from '@angular/common';\nimport { Injectable, InjectionToken, computed, effect, inject, signal } from '@angular/core';\nimport { STAR_THEME_DEFAULT_STORAGE_KEY } from './theme-key';\n\n/** `'system'` follows the operating system setting (`prefers-color-scheme`). */\nexport type StarThemeMode = 'system' | 'light' | 'dark';\n\nexport { STAR_THEME_DEFAULT_STORAGE_KEY };\n\n/**\n * `localStorage` key of the saved theme choice. Provide another value when two applications\n * on one origin must keep separate choices. The first-paint script must use the same key.\n */\nexport const STAR_THEME_STORAGE_KEY = new InjectionToken<string>('STAR_THEME_STORAGE_KEY', {\n providedIn: 'root',\n factory: () => STAR_THEME_DEFAULT_STORAGE_KEY,\n});\n\nconst MODES: readonly StarThemeMode[] = ['system', 'light', 'dark'];\n\n/**\n * Color theme of the application. The StarNG tokens change with `data-theme` on `<html>`\n * (`@star-ng/ui/styles/_tokens.scss`); this service sets that attribute and remembers the choice\n * in the browser (`localStorage`). Inject it in the root component, so the theme applies on\n * every page.\n *\n * The service is optional: an application that has one fixed theme does not need it.\n */\n@Injectable({ providedIn: 'root' })\nexport class StarThemeService {\n private readonly document = inject(DOCUMENT);\n private readonly storageKey = inject(STAR_THEME_STORAGE_KEY);\n private readonly view = this.document.defaultView;\n private readonly systemQuery = this.view?.matchMedia?.('(prefers-color-scheme: dark)') ?? null;\n private readonly systemDark = signal(this.systemQuery?.matches ?? false);\n\n /** The user's choice. */\n readonly mode = signal<StarThemeMode>(this.stored());\n /** The theme in use now: `'system'` resolved to light or dark. */\n readonly theme = computed<'light' | 'dark'>(() => {\n const mode = this.mode();\n if (mode === 'system') return this.systemDark() ? 'dark' : 'light';\n return mode;\n });\n\n constructor() {\n this.systemQuery?.addEventListener?.('change', (event) => this.systemDark.set(event.matches));\n effect(() => this.document.documentElement.setAttribute('data-theme', this.theme()));\n }\n\n setMode(mode: StarThemeMode): void {\n this.mode.set(mode);\n try {\n this.view?.localStorage.setItem(this.storageKey, mode);\n } catch {\n // Storage can be blocked (private mode): the choice then lasts for this visit only.\n }\n }\n\n private stored(): StarThemeMode {\n try {\n const value = this.view?.localStorage.getItem(this.storageKey);\n return MODES.includes(value as StarThemeMode) ? (value as StarThemeMode) : 'system';\n } catch {\n return 'system';\n }\n }\n}\n"],"mappings":"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"}
@@ -0,0 +1,298 @@
1
+ import * as i0 from "@angular/core";
2
+ import { ChangeDetectionStrategy, Component, DestroyRef, ElementRef, Service, afterRenderEffect, computed, inject, input, signal } from "@angular/core";
3
+ import { STAR_UI_TEXT } from "@star-ng/ui/core";
4
+ var StarToastService = class StarToastService {
5
+ items = signal([], ...ngDevMode ? [{ debugName: "items" }] : /* istanbul ignore next */ []);
6
+ timers = /* @__PURE__ */ new Map();
7
+ nextId = 1;
8
+ messages = this.items.asReadonly();
9
+ preventDuplicates = true;
10
+ constructor() {
11
+ inject(DestroyRef).onDestroy(() => this.clear());
12
+ }
13
+ show(options) {
14
+ const severity = options.severity ?? "info";
15
+ if (this.preventDuplicates) {
16
+ const duplicate = this.items().find((item) => item.summary === options.summary && item.detail === options.detail && item.severity === severity && item.key === options.key);
17
+ if (duplicate) return duplicate.id;
18
+ }
19
+ const message = {
20
+ id: this.nextId++,
21
+ severity,
22
+ summary: options.summary,
23
+ detail: options.detail,
24
+ life: options.life ?? 5e3,
25
+ sticky: options.sticky ?? false,
26
+ key: options.key
27
+ };
28
+ this.items.update((items) => [...items, message]);
29
+ if (!message.sticky) this.startTimer(message.id, message.life);
30
+ return message.id;
31
+ }
32
+ success(summary, detail) {
33
+ return this.show({
34
+ severity: "success",
35
+ summary,
36
+ detail
37
+ });
38
+ }
39
+ info(summary, detail) {
40
+ return this.show({
41
+ severity: "info",
42
+ summary,
43
+ detail
44
+ });
45
+ }
46
+ warn(summary, detail) {
47
+ return this.show({
48
+ severity: "warn",
49
+ summary,
50
+ detail
51
+ });
52
+ }
53
+ error(summary, detail) {
54
+ return this.show({
55
+ severity: "error",
56
+ summary,
57
+ detail,
58
+ life: 8e3
59
+ });
60
+ }
61
+ remove(id) {
62
+ const timer = this.timers.get(id);
63
+ if (timer) clearTimeout(timer.handle);
64
+ this.timers.delete(id);
65
+ this.items.update((items) => items.filter((item) => item.id !== id));
66
+ }
67
+ clear(key) {
68
+ for (const item of this.items()) if (key === void 0 || item.key === key) this.remove(item.id);
69
+ }
70
+ pause(id) {
71
+ const timer = this.timers.get(id);
72
+ if (!timer?.handle) return;
73
+ clearTimeout(timer.handle);
74
+ timer.handle = void 0;
75
+ timer.remaining -= Date.now() - timer.startedAt;
76
+ }
77
+ resume(id) {
78
+ const timer = this.timers.get(id);
79
+ if (!timer || timer.handle) return;
80
+ this.startTimer(id, Math.max(timer.remaining, 1e3));
81
+ }
82
+ startTimer(id, ms) {
83
+ this.timers.set(id, {
84
+ handle: setTimeout(() => this.remove(id), ms),
85
+ remaining: ms,
86
+ startedAt: Date.now()
87
+ });
88
+ }
89
+ static ɵfac = i0.ɵɵngDeclareFactory({
90
+ minVersion: "12.0.0",
91
+ version: "22.2.6",
92
+ ngImport: i0,
93
+ type: StarToastService,
94
+ deps: [],
95
+ target: i0.ɵɵFactoryTarget.Service
96
+ });
97
+ static ɵprov = i0.ɵɵngDeclareService({
98
+ minVersion: "22.0.0",
99
+ version: "22.2.6",
100
+ ngImport: i0,
101
+ type: StarToastService
102
+ });
103
+ };
104
+ i0.ɵɵngDeclareClassMetadata({
105
+ minVersion: "12.0.0",
106
+ version: "22.2.6",
107
+ ngImport: i0,
108
+ type: StarToastService,
109
+ decorators: [{ type: Service }],
110
+ ctorParameters: () => []
111
+ });
112
+ const ICONS = {
113
+ success: "ph-fill ph-check-circle",
114
+ info: "ph-fill ph-info",
115
+ warn: "ph-fill ph-warning",
116
+ error: "ph-fill ph-x-circle"
117
+ };
118
+ var StarToast = class StarToast {
119
+ toasts = inject(StarToastService);
120
+ text = inject(STAR_UI_TEXT);
121
+ host = inject(ElementRef);
122
+ position = input("top-right", ...ngDevMode ? [{ debugName: "position" }] : /* istanbul ignore next */ []);
123
+ key = input(void 0, ...ngDevMode ? [{ debugName: "key" }] : /* istanbul ignore next */ []);
124
+ stackLimit = input(5, ...ngDevMode ? [{ debugName: "stackLimit" }] : /* istanbul ignore next */ []);
125
+ visible = computed(() => this.toasts.messages().filter((message) => message.key === this.key()).slice(0, this.stackLimit()), ...ngDevMode ? [{ debugName: "visible" }] : /* istanbul ignore next */ []);
126
+ constructor() {
127
+ afterRenderEffect({ write: () => {
128
+ const element = this.host.nativeElement;
129
+ const count = this.visible().length;
130
+ if (typeof element.showPopover !== "function") return;
131
+ if (element.matches(":popover-open")) element.hidePopover();
132
+ if (count > 0) element.showPopover();
133
+ } });
134
+ }
135
+ icon(severity) {
136
+ return ICONS[severity];
137
+ }
138
+ static ɵfac = i0.ɵɵngDeclareFactory({
139
+ minVersion: "12.0.0",
140
+ version: "22.2.6",
141
+ ngImport: i0,
142
+ type: StarToast,
143
+ deps: [],
144
+ target: i0.ɵɵFactoryTarget.Component
145
+ });
146
+ static ɵcmp = i0.ɵɵngDeclareComponent({
147
+ minVersion: "17.0.0",
148
+ version: "22.2.6",
149
+ type: StarToast,
150
+ isStandalone: true,
151
+ selector: "star-toast",
152
+ inputs: {
153
+ position: {
154
+ classPropertyName: "position",
155
+ publicName: "position",
156
+ isSignal: true,
157
+ isRequired: false,
158
+ transformFunction: null
159
+ },
160
+ key: {
161
+ classPropertyName: "key",
162
+ publicName: "key",
163
+ isSignal: true,
164
+ isRequired: false,
165
+ transformFunction: null
166
+ },
167
+ stackLimit: {
168
+ classPropertyName: "stackLimit",
169
+ publicName: "stackLimit",
170
+ isSignal: true,
171
+ isRequired: false,
172
+ transformFunction: null
173
+ }
174
+ },
175
+ host: {
176
+ attributes: {
177
+ "popover": "manual",
178
+ "role": "region"
179
+ },
180
+ properties: {
181
+ "class": "'star-toast-stack star-toast-stack--' + position()",
182
+ "attr.aria-label": "text.notifications"
183
+ },
184
+ classAttribute: "star-toast-stack"
185
+ },
186
+ ngImport: i0,
187
+ template: `
188
+ @for (message of visible(); track message.id) {
189
+ <div
190
+ class="star-toast"
191
+ [class]="'star-toast star-toast--' + message.severity"
192
+ [attr.role]="message.severity === 'error' ? 'alert' : 'status'"
193
+ (mouseenter)="toasts.pause(message.id)"
194
+ (mouseleave)="toasts.resume(message.id)"
195
+ (focusin)="toasts.pause(message.id)"
196
+ (focusout)="toasts.resume(message.id)"
197
+ >
198
+ <i class="star-toast__icon" [class]="icon(message.severity)" aria-hidden="true"></i>
199
+ <div class="star-toast__copy">
200
+ <p class="star-toast__summary">{{ message.summary }}</p>
201
+ @if (message.detail) {
202
+ <p class="star-toast__detail">{{ message.detail }}</p>
203
+ }
204
+ </div>
205
+ <button
206
+ type="button"
207
+ class="star-toast__close"
208
+ [attr.aria-label]="text.close"
209
+ (click)="toasts.remove(message.id)"
210
+ >
211
+ <i class="ph-bold ph-x" aria-hidden="true"></i>
212
+ </button>
213
+ </div>
214
+ }
215
+ `,
216
+ isInline: true,
217
+ changeDetection: i0.ChangeDetectionStrategy.OnPush
218
+ });
219
+ };
220
+ i0.ɵɵngDeclareClassMetadata({
221
+ minVersion: "12.0.0",
222
+ version: "22.2.6",
223
+ ngImport: i0,
224
+ type: StarToast,
225
+ decorators: [{
226
+ type: Component,
227
+ args: [{
228
+ selector: "star-toast",
229
+ changeDetection: ChangeDetectionStrategy.OnPush,
230
+ host: {
231
+ class: "star-toast-stack",
232
+ popover: "manual",
233
+ "[class]": "'star-toast-stack star-toast-stack--' + position()",
234
+ "[attr.aria-label]": "text.notifications",
235
+ role: "region"
236
+ },
237
+ template: `
238
+ @for (message of visible(); track message.id) {
239
+ <div
240
+ class="star-toast"
241
+ [class]="'star-toast star-toast--' + message.severity"
242
+ [attr.role]="message.severity === 'error' ? 'alert' : 'status'"
243
+ (mouseenter)="toasts.pause(message.id)"
244
+ (mouseleave)="toasts.resume(message.id)"
245
+ (focusin)="toasts.pause(message.id)"
246
+ (focusout)="toasts.resume(message.id)"
247
+ >
248
+ <i class="star-toast__icon" [class]="icon(message.severity)" aria-hidden="true"></i>
249
+ <div class="star-toast__copy">
250
+ <p class="star-toast__summary">{{ message.summary }}</p>
251
+ @if (message.detail) {
252
+ <p class="star-toast__detail">{{ message.detail }}</p>
253
+ }
254
+ </div>
255
+ <button
256
+ type="button"
257
+ class="star-toast__close"
258
+ [attr.aria-label]="text.close"
259
+ (click)="toasts.remove(message.id)"
260
+ >
261
+ <i class="ph-bold ph-x" aria-hidden="true"></i>
262
+ </button>
263
+ </div>
264
+ }
265
+ `
266
+ }]
267
+ }],
268
+ ctorParameters: () => [],
269
+ propDecorators: {
270
+ position: [{
271
+ type: i0.Input,
272
+ args: [{
273
+ isSignal: true,
274
+ alias: "position",
275
+ required: false
276
+ }]
277
+ }],
278
+ key: [{
279
+ type: i0.Input,
280
+ args: [{
281
+ isSignal: true,
282
+ alias: "key",
283
+ required: false
284
+ }]
285
+ }],
286
+ stackLimit: [{
287
+ type: i0.Input,
288
+ args: [{
289
+ isSignal: true,
290
+ alias: "stackLimit",
291
+ required: false
292
+ }]
293
+ }]
294
+ }
295
+ });
296
+ export { StarToast, StarToastService };
297
+
298
+ //# sourceMappingURL=star-ng-ui-toast.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"star-ng-ui-toast.mjs","names":[],"sources":["../../../projects/star-ng/toast/toast.ts"],"sourcesContent":["import {\n afterRenderEffect,\n ChangeDetectionStrategy,\n Component,\n computed,\n DestroyRef,\n ElementRef,\n inject,\n input,\n Service,\n signal,\n} from '@angular/core';\nimport { STAR_UI_TEXT } from '@star-ng/ui/core';\n\nexport type StarToastSeverity = 'success' | 'info' | 'warn' | 'error';\n\nexport interface StarToastOptions {\n readonly severity?: StarToastSeverity;\n readonly summary: string;\n readonly detail?: string;\n /** Milliseconds before auto close (default 5000). */\n readonly life?: number;\n /** Stays until the user closes it. */\n readonly sticky?: boolean;\n /** Targets a specific `<star-toast key=\"...\">`. */\n readonly key?: string;\n}\n\nexport interface StarToastMessage extends Required<Omit<StarToastOptions, 'detail' | 'key'>> {\n readonly id: number;\n readonly detail?: string;\n readonly key?: string;\n}\n\ninterface Timer {\n handle: ReturnType<typeof setTimeout> | undefined;\n remaining: number;\n startedAt: number;\n}\n\n/**\n * Toast notifications (PrimeNG `MessageService` + `p-toast`): severities, auto-close with\n * pause on hover / focus, sticky messages, duplicate suppression and a visible-stack limit.\n *\n * `inject(StarToastService).success('Saved', 'Order ORD-102 was updated.')`\n */\n@Service()\nexport class StarToastService {\n private readonly items = signal<readonly StarToastMessage[]>([]);\n private readonly timers = new Map<number, Timer>();\n private nextId = 1;\n\n readonly messages = this.items.asReadonly();\n /** Identical summary + detail while still visible is ignored. */\n preventDuplicates = true;\n\n constructor() {\n inject(DestroyRef).onDestroy(() => this.clear());\n }\n\n show(options: StarToastOptions): number {\n const severity = options.severity ?? 'info';\n if (this.preventDuplicates) {\n const duplicate = this.items().find(\n (item) =>\n item.summary === options.summary &&\n item.detail === options.detail &&\n item.severity === severity &&\n item.key === options.key,\n );\n if (duplicate) return duplicate.id;\n }\n const message: StarToastMessage = {\n id: this.nextId++,\n severity,\n summary: options.summary,\n detail: options.detail,\n life: options.life ?? 5000,\n sticky: options.sticky ?? false,\n key: options.key,\n };\n this.items.update((items) => [...items, message]);\n if (!message.sticky) this.startTimer(message.id, message.life);\n return message.id;\n }\n\n success(summary: string, detail?: string): number {\n return this.show({ severity: 'success', summary, detail });\n }\n info(summary: string, detail?: string): number {\n return this.show({ severity: 'info', summary, detail });\n }\n warn(summary: string, detail?: string): number {\n return this.show({ severity: 'warn', summary, detail });\n }\n error(summary: string, detail?: string): number {\n return this.show({ severity: 'error', summary, detail, life: 8000 });\n }\n\n remove(id: number): void {\n const timer = this.timers.get(id);\n if (timer) clearTimeout(timer.handle);\n this.timers.delete(id);\n this.items.update((items) => items.filter((item) => item.id !== id));\n }\n\n /** Removes all messages, or only those of one `key`. */\n clear(key?: string): void {\n for (const item of this.items()) {\n if (key === undefined || item.key === key) this.remove(item.id);\n }\n }\n\n pause(id: number): void {\n const timer = this.timers.get(id);\n if (!timer?.handle) return;\n clearTimeout(timer.handle);\n timer.handle = undefined;\n timer.remaining -= Date.now() - timer.startedAt;\n }\n\n resume(id: number): void {\n const timer = this.timers.get(id);\n if (!timer || timer.handle) return;\n this.startTimer(id, Math.max(timer.remaining, 1000));\n }\n\n private startTimer(id: number, ms: number): void {\n this.timers.set(id, {\n handle: setTimeout(() => this.remove(id), ms),\n remaining: ms,\n startedAt: Date.now(),\n });\n }\n}\n\nconst ICONS: Record<StarToastSeverity, string> = {\n success: 'ph-fill ph-check-circle',\n info: 'ph-fill ph-info',\n warn: 'ph-fill ph-warning',\n error: 'ph-fill ph-x-circle',\n};\n\n/**\n * Toast outlet. Place once in the app shell. It renders as a manual popover, so toasts stay\n * above open modal dialogs (top layer).\n */\n@Component({\n selector: 'star-toast',\n changeDetection: ChangeDetectionStrategy.OnPush,\n host: {\n class: 'star-toast-stack',\n popover: 'manual',\n '[class]': \"'star-toast-stack star-toast-stack--' + position()\",\n '[attr.aria-label]': 'text.notifications',\n role: 'region',\n },\n template: `\n @for (message of visible(); track message.id) {\n <div\n class=\"star-toast\"\n [class]=\"'star-toast star-toast--' + message.severity\"\n [attr.role]=\"message.severity === 'error' ? 'alert' : 'status'\"\n (mouseenter)=\"toasts.pause(message.id)\"\n (mouseleave)=\"toasts.resume(message.id)\"\n (focusin)=\"toasts.pause(message.id)\"\n (focusout)=\"toasts.resume(message.id)\"\n >\n <i class=\"star-toast__icon\" [class]=\"icon(message.severity)\" aria-hidden=\"true\"></i>\n <div class=\"star-toast__copy\">\n <p class=\"star-toast__summary\">{{ message.summary }}</p>\n @if (message.detail) {\n <p class=\"star-toast__detail\">{{ message.detail }}</p>\n }\n </div>\n <button\n type=\"button\"\n class=\"star-toast__close\"\n [attr.aria-label]=\"text.close\"\n (click)=\"toasts.remove(message.id)\"\n >\n <i class=\"ph-bold ph-x\" aria-hidden=\"true\"></i>\n </button>\n </div>\n }\n `,\n})\nexport class StarToast {\n protected readonly toasts = inject(StarToastService);\n protected readonly text = inject(STAR_UI_TEXT);\n private readonly host = inject<ElementRef<HTMLElement>>(ElementRef);\n\n /**\n * Corner of the screen. `-left` and `-right` are physical; `-start` and `-end` follow the\n * writing direction (the start corner is on the right in right-to-left).\n */\n readonly position = input<\n | 'top-right'\n | 'top-left'\n | 'top-start'\n | 'top-end'\n | 'top-center'\n | 'bottom-right'\n | 'bottom-left'\n | 'bottom-start'\n | 'bottom-end'\n | 'bottom-center'\n >('top-right');\n readonly key = input<string | undefined>(undefined);\n /** Newest messages beyond this count wait until older ones close. */\n readonly stackLimit = input(5);\n\n protected readonly visible = computed(() =>\n this.toasts\n .messages()\n .filter((message) => message.key === this.key())\n .slice(0, this.stackLimit()),\n );\n\n constructor() {\n afterRenderEffect({\n write: () => {\n const element = this.host.nativeElement;\n const count = this.visible().length;\n if (typeof element.showPopover !== 'function') return;\n // Re-open to move the stack above any dialog opened after it.\n if (element.matches(':popover-open')) element.hidePopover();\n if (count > 0) element.showPopover();\n },\n });\n }\n\n protected icon(severity: StarToastSeverity): string {\n return ICONS[severity];\n }\n}\n"],"mappings":"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"}