@frame-kit/ui-ng 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (220) hide show
  1. package/COMPONENTS.md +683 -0
  2. package/DEVELOPMENT_GUIDE.md +1102 -0
  3. package/LICENSE +21 -0
  4. package/README.md +69 -0
  5. package/THEMING.md +130 -0
  6. package/core/headline/README.md +121 -0
  7. package/core/icon/README.md +173 -0
  8. package/core/image/README.md +210 -0
  9. package/core/link/README.md +297 -0
  10. package/core/separator/README.md +145 -0
  11. package/core/text/README.md +240 -0
  12. package/directives/infinite-scroll/README.md +102 -0
  13. package/directives/spotlight/README.md +154 -0
  14. package/directives/tooltip/README.md +147 -0
  15. package/docs/endpoint-link/README.md +142 -0
  16. package/docs/method-badge/README.md +154 -0
  17. package/fesm2022/frame-kit-ui-ng-core-headline.mjs +122 -0
  18. package/fesm2022/frame-kit-ui-ng-core-headline.mjs.map +1 -0
  19. package/fesm2022/frame-kit-ui-ng-core-icon.mjs +189 -0
  20. package/fesm2022/frame-kit-ui-ng-core-icon.mjs.map +1 -0
  21. package/fesm2022/frame-kit-ui-ng-core-image.mjs +123 -0
  22. package/fesm2022/frame-kit-ui-ng-core-image.mjs.map +1 -0
  23. package/fesm2022/frame-kit-ui-ng-core-link.mjs +369 -0
  24. package/fesm2022/frame-kit-ui-ng-core-link.mjs.map +1 -0
  25. package/fesm2022/frame-kit-ui-ng-core-separator.mjs +59 -0
  26. package/fesm2022/frame-kit-ui-ng-core-separator.mjs.map +1 -0
  27. package/fesm2022/frame-kit-ui-ng-core-text.mjs +204 -0
  28. package/fesm2022/frame-kit-ui-ng-core-text.mjs.map +1 -0
  29. package/fesm2022/frame-kit-ui-ng-directives-infinite-scroll.mjs +74 -0
  30. package/fesm2022/frame-kit-ui-ng-directives-infinite-scroll.mjs.map +1 -0
  31. package/fesm2022/frame-kit-ui-ng-directives-spotlight.mjs +76 -0
  32. package/fesm2022/frame-kit-ui-ng-directives-spotlight.mjs.map +1 -0
  33. package/fesm2022/frame-kit-ui-ng-directives-tooltip.mjs +425 -0
  34. package/fesm2022/frame-kit-ui-ng-directives-tooltip.mjs.map +1 -0
  35. package/fesm2022/frame-kit-ui-ng-docs-endpoint-link.mjs +63 -0
  36. package/fesm2022/frame-kit-ui-ng-docs-endpoint-link.mjs.map +1 -0
  37. package/fesm2022/frame-kit-ui-ng-docs-method-badge.mjs +43 -0
  38. package/fesm2022/frame-kit-ui-ng-docs-method-badge.mjs.map +1 -0
  39. package/fesm2022/frame-kit-ui-ng-forms.mjs +3632 -0
  40. package/fesm2022/frame-kit-ui-ng-forms.mjs.map +1 -0
  41. package/fesm2022/frame-kit-ui-ng-layouts-app-shell.mjs +239 -0
  42. package/fesm2022/frame-kit-ui-ng-layouts-app-shell.mjs.map +1 -0
  43. package/fesm2022/frame-kit-ui-ng-layouts-content-split.mjs +132 -0
  44. package/fesm2022/frame-kit-ui-ng-layouts-content-split.mjs.map +1 -0
  45. package/fesm2022/frame-kit-ui-ng-services-overlay-orchestrator.mjs +133 -0
  46. package/fesm2022/frame-kit-ui-ng-services-overlay-orchestrator.mjs.map +1 -0
  47. package/fesm2022/frame-kit-ui-ng-services-spotlight.mjs +60 -0
  48. package/fesm2022/frame-kit-ui-ng-services-spotlight.mjs.map +1 -0
  49. package/fesm2022/frame-kit-ui-ng-services-toast.mjs +166 -0
  50. package/fesm2022/frame-kit-ui-ng-services-toast.mjs.map +1 -0
  51. package/fesm2022/frame-kit-ui-ng-ui-accordion.mjs +214 -0
  52. package/fesm2022/frame-kit-ui-ng-ui-accordion.mjs.map +1 -0
  53. package/fesm2022/frame-kit-ui-ng-ui-alert.mjs +82 -0
  54. package/fesm2022/frame-kit-ui-ng-ui-alert.mjs.map +1 -0
  55. package/fesm2022/frame-kit-ui-ng-ui-avatar-stack.mjs +76 -0
  56. package/fesm2022/frame-kit-ui-ng-ui-avatar-stack.mjs.map +1 -0
  57. package/fesm2022/frame-kit-ui-ng-ui-avatar.mjs +81 -0
  58. package/fesm2022/frame-kit-ui-ng-ui-avatar.mjs.map +1 -0
  59. package/fesm2022/frame-kit-ui-ng-ui-badge.mjs +81 -0
  60. package/fesm2022/frame-kit-ui-ng-ui-badge.mjs.map +1 -0
  61. package/fesm2022/frame-kit-ui-ng-ui-breadcrumb.mjs +68 -0
  62. package/fesm2022/frame-kit-ui-ng-ui-breadcrumb.mjs.map +1 -0
  63. package/fesm2022/frame-kit-ui-ng-ui-button.mjs +108 -0
  64. package/fesm2022/frame-kit-ui-ng-ui-button.mjs.map +1 -0
  65. package/fesm2022/frame-kit-ui-ng-ui-callout.mjs +58 -0
  66. package/fesm2022/frame-kit-ui-ng-ui-callout.mjs.map +1 -0
  67. package/fesm2022/frame-kit-ui-ng-ui-card.mjs +70 -0
  68. package/fesm2022/frame-kit-ui-ng-ui-card.mjs.map +1 -0
  69. package/fesm2022/frame-kit-ui-ng-ui-copyable-field.mjs +113 -0
  70. package/fesm2022/frame-kit-ui-ng-ui-copyable-field.mjs.map +1 -0
  71. package/fesm2022/frame-kit-ui-ng-ui-data-table.mjs +1288 -0
  72. package/fesm2022/frame-kit-ui-ng-ui-data-table.mjs.map +1 -0
  73. package/fesm2022/frame-kit-ui-ng-ui-dialog.mjs +456 -0
  74. package/fesm2022/frame-kit-ui-ng-ui-dialog.mjs.map +1 -0
  75. package/fesm2022/frame-kit-ui-ng-ui-drawer.mjs +398 -0
  76. package/fesm2022/frame-kit-ui-ng-ui-drawer.mjs.map +1 -0
  77. package/fesm2022/frame-kit-ui-ng-ui-dropdown-menu.mjs +398 -0
  78. package/fesm2022/frame-kit-ui-ng-ui-dropdown-menu.mjs.map +1 -0
  79. package/fesm2022/frame-kit-ui-ng-ui-editable-field.mjs +125 -0
  80. package/fesm2022/frame-kit-ui-ng-ui-editable-field.mjs.map +1 -0
  81. package/fesm2022/frame-kit-ui-ng-ui-icon-badge.mjs +113 -0
  82. package/fesm2022/frame-kit-ui-ng-ui-icon-badge.mjs.map +1 -0
  83. package/fesm2022/frame-kit-ui-ng-ui-icon-list.mjs +111 -0
  84. package/fesm2022/frame-kit-ui-ng-ui-icon-list.mjs.map +1 -0
  85. package/fesm2022/frame-kit-ui-ng-ui-inline-edit.mjs +103 -0
  86. package/fesm2022/frame-kit-ui-ng-ui-inline-edit.mjs.map +1 -0
  87. package/fesm2022/frame-kit-ui-ng-ui-list-editor.mjs +135 -0
  88. package/fesm2022/frame-kit-ui-ng-ui-list-editor.mjs.map +1 -0
  89. package/fesm2022/frame-kit-ui-ng-ui-loader.mjs +81 -0
  90. package/fesm2022/frame-kit-ui-ng-ui-loader.mjs.map +1 -0
  91. package/fesm2022/frame-kit-ui-ng-ui-menu-item.mjs +79 -0
  92. package/fesm2022/frame-kit-ui-ng-ui-menu-item.mjs.map +1 -0
  93. package/fesm2022/frame-kit-ui-ng-ui-nav-brand.mjs +40 -0
  94. package/fesm2022/frame-kit-ui-ng-ui-nav-brand.mjs.map +1 -0
  95. package/fesm2022/frame-kit-ui-ng-ui-nav-group.mjs +110 -0
  96. package/fesm2022/frame-kit-ui-ng-ui-nav-group.mjs.map +1 -0
  97. package/fesm2022/frame-kit-ui-ng-ui-nav-separator.mjs +91 -0
  98. package/fesm2022/frame-kit-ui-ng-ui-nav-separator.mjs.map +1 -0
  99. package/fesm2022/frame-kit-ui-ng-ui-node-tree-breadcrumb.mjs +86 -0
  100. package/fesm2022/frame-kit-ui-ng-ui-node-tree-breadcrumb.mjs.map +1 -0
  101. package/fesm2022/frame-kit-ui-ng-ui-node-tree.mjs +443 -0
  102. package/fesm2022/frame-kit-ui-ng-ui-node-tree.mjs.map +1 -0
  103. package/fesm2022/frame-kit-ui-ng-ui-note.mjs +56 -0
  104. package/fesm2022/frame-kit-ui-ng-ui-note.mjs.map +1 -0
  105. package/fesm2022/frame-kit-ui-ng-ui-numbered-list.mjs +105 -0
  106. package/fesm2022/frame-kit-ui-ng-ui-numbered-list.mjs.map +1 -0
  107. package/fesm2022/frame-kit-ui-ng-ui-pagination.mjs +110 -0
  108. package/fesm2022/frame-kit-ui-ng-ui-pagination.mjs.map +1 -0
  109. package/fesm2022/frame-kit-ui-ng-ui-progress-bar.mjs +129 -0
  110. package/fesm2022/frame-kit-ui-ng-ui-progress-bar.mjs.map +1 -0
  111. package/fesm2022/frame-kit-ui-ng-ui-sidenav-link.mjs +42 -0
  112. package/fesm2022/frame-kit-ui-ng-ui-sidenav-link.mjs.map +1 -0
  113. package/fesm2022/frame-kit-ui-ng-ui-tabs.mjs +894 -0
  114. package/fesm2022/frame-kit-ui-ng-ui-tabs.mjs.map +1 -0
  115. package/fesm2022/frame-kit-ui-ng-ui-timeline.mjs +81 -0
  116. package/fesm2022/frame-kit-ui-ng-ui-timeline.mjs.map +1 -0
  117. package/fesm2022/frame-kit-ui-ng-ui-toast.mjs +179 -0
  118. package/fesm2022/frame-kit-ui-ng-ui-toast.mjs.map +1 -0
  119. package/fesm2022/frame-kit-ui-ng-ui-user-menu.mjs +143 -0
  120. package/fesm2022/frame-kit-ui-ng-ui-user-menu.mjs.map +1 -0
  121. package/fesm2022/frame-kit-ui-ng-ui-wizard-dialog.mjs +191 -0
  122. package/fesm2022/frame-kit-ui-ng-ui-wizard-dialog.mjs.map +1 -0
  123. package/fesm2022/frame-kit-ui-ng.mjs +58 -0
  124. package/fesm2022/frame-kit-ui-ng.mjs.map +1 -0
  125. package/layouts/app-shell/README.md +357 -0
  126. package/layouts/content-split/README.md +180 -0
  127. package/package.json +253 -0
  128. package/services/overlay-orchestrator/README.md +184 -0
  129. package/services/spotlight/README.md +61 -0
  130. package/services/toast/README.md +118 -0
  131. package/types/frame-kit-ui-ng-core-headline.d.ts +38 -0
  132. package/types/frame-kit-ui-ng-core-icon.d.ts +74 -0
  133. package/types/frame-kit-ui-ng-core-image.d.ts +93 -0
  134. package/types/frame-kit-ui-ng-core-link.d.ts +251 -0
  135. package/types/frame-kit-ui-ng-core-separator.d.ts +28 -0
  136. package/types/frame-kit-ui-ng-core-text.d.ts +186 -0
  137. package/types/frame-kit-ui-ng-directives-infinite-scroll.d.ts +42 -0
  138. package/types/frame-kit-ui-ng-directives-spotlight.d.ts +51 -0
  139. package/types/frame-kit-ui-ng-directives-tooltip.d.ts +70 -0
  140. package/types/frame-kit-ui-ng-docs-endpoint-link.d.ts +43 -0
  141. package/types/frame-kit-ui-ng-docs-method-badge.d.ts +30 -0
  142. package/types/frame-kit-ui-ng-forms.d.ts +1674 -0
  143. package/types/frame-kit-ui-ng-layouts-app-shell.d.ts +75 -0
  144. package/types/frame-kit-ui-ng-layouts-content-split.d.ts +43 -0
  145. package/types/frame-kit-ui-ng-services-overlay-orchestrator.d.ts +96 -0
  146. package/types/frame-kit-ui-ng-services-spotlight.d.ts +32 -0
  147. package/types/frame-kit-ui-ng-services-toast.d.ts +100 -0
  148. package/types/frame-kit-ui-ng-ui-accordion.d.ts +86 -0
  149. package/types/frame-kit-ui-ng-ui-alert.d.ts +34 -0
  150. package/types/frame-kit-ui-ng-ui-avatar-stack.d.ts +38 -0
  151. package/types/frame-kit-ui-ng-ui-avatar.d.ts +36 -0
  152. package/types/frame-kit-ui-ng-ui-badge.d.ts +33 -0
  153. package/types/frame-kit-ui-ng-ui-breadcrumb.d.ts +45 -0
  154. package/types/frame-kit-ui-ng-ui-button.d.ts +48 -0
  155. package/types/frame-kit-ui-ng-ui-callout.d.ts +26 -0
  156. package/types/frame-kit-ui-ng-ui-card.d.ts +30 -0
  157. package/types/frame-kit-ui-ng-ui-copyable-field.d.ts +62 -0
  158. package/types/frame-kit-ui-ng-ui-data-table.d.ts +482 -0
  159. package/types/frame-kit-ui-ng-ui-dialog.d.ts +166 -0
  160. package/types/frame-kit-ui-ng-ui-drawer.d.ts +130 -0
  161. package/types/frame-kit-ui-ng-ui-dropdown-menu.d.ts +77 -0
  162. package/types/frame-kit-ui-ng-ui-editable-field.d.ts +65 -0
  163. package/types/frame-kit-ui-ng-ui-icon-badge.d.ts +45 -0
  164. package/types/frame-kit-ui-ng-ui-icon-list.d.ts +67 -0
  165. package/types/frame-kit-ui-ng-ui-inline-edit.d.ts +44 -0
  166. package/types/frame-kit-ui-ng-ui-list-editor.d.ts +56 -0
  167. package/types/frame-kit-ui-ng-ui-loader.d.ts +32 -0
  168. package/types/frame-kit-ui-ng-ui-menu-item.d.ts +27 -0
  169. package/types/frame-kit-ui-ng-ui-nav-brand.d.ts +25 -0
  170. package/types/frame-kit-ui-ng-ui-nav-group.d.ts +60 -0
  171. package/types/frame-kit-ui-ng-ui-nav-separator.d.ts +33 -0
  172. package/types/frame-kit-ui-ng-ui-node-tree-breadcrumb.d.ts +35 -0
  173. package/types/frame-kit-ui-ng-ui-node-tree.d.ts +135 -0
  174. package/types/frame-kit-ui-ng-ui-note.d.ts +22 -0
  175. package/types/frame-kit-ui-ng-ui-numbered-list.d.ts +52 -0
  176. package/types/frame-kit-ui-ng-ui-pagination.d.ts +49 -0
  177. package/types/frame-kit-ui-ng-ui-progress-bar.d.ts +50 -0
  178. package/types/frame-kit-ui-ng-ui-sidenav-link.d.ts +24 -0
  179. package/types/frame-kit-ui-ng-ui-tabs.d.ts +266 -0
  180. package/types/frame-kit-ui-ng-ui-timeline.d.ts +42 -0
  181. package/types/frame-kit-ui-ng-ui-toast.d.ts +56 -0
  182. package/types/frame-kit-ui-ng-ui-user-menu.d.ts +87 -0
  183. package/types/frame-kit-ui-ng-ui-wizard-dialog.d.ts +116 -0
  184. package/types/frame-kit-ui-ng.d.ts +53 -0
  185. package/ui/accordion/README.md +261 -0
  186. package/ui/alert/README.md +211 -0
  187. package/ui/avatar/README.md +167 -0
  188. package/ui/avatar-stack/README.md +164 -0
  189. package/ui/badge/README.md +162 -0
  190. package/ui/breadcrumb/README.md +240 -0
  191. package/ui/button/README.md +184 -0
  192. package/ui/callout/README.md +159 -0
  193. package/ui/card/README.md +174 -0
  194. package/ui/copyable-field/README.md +235 -0
  195. package/ui/data-table/README.md +408 -0
  196. package/ui/dialog/README.md +222 -0
  197. package/ui/drawer/README.md +274 -0
  198. package/ui/dropdown-menu/README.md +336 -0
  199. package/ui/editable-field/README.md +171 -0
  200. package/ui/icon-badge/README.md +131 -0
  201. package/ui/icon-list/README.md +205 -0
  202. package/ui/inline-edit/README.md +135 -0
  203. package/ui/list-editor/README.md +162 -0
  204. package/ui/loader/README.md +160 -0
  205. package/ui/menu-item/README.md +204 -0
  206. package/ui/nav-brand/README.md +111 -0
  207. package/ui/nav-group/README.md +145 -0
  208. package/ui/nav-separator/README.md +44 -0
  209. package/ui/node-tree/README.md +278 -0
  210. package/ui/node-tree-breadcrumb/README.md +164 -0
  211. package/ui/note/README.md +146 -0
  212. package/ui/numbered-list/README.md +187 -0
  213. package/ui/pagination/README.md +174 -0
  214. package/ui/progress-bar/README.md +223 -0
  215. package/ui/sidenav-link/README.md +214 -0
  216. package/ui/tabs/README.md +204 -0
  217. package/ui/timeline/README.md +285 -0
  218. package/ui/toast/README.md +243 -0
  219. package/ui/user-menu/README.md +260 -0
  220. package/ui/wizard-dialog/README.md +283 -0
@@ -0,0 +1,425 @@
1
+ import * as i0 from '@angular/core';
2
+ import { input, inject, ElementRef, Renderer2, NgZone, DestroyRef, effect, Directive } from '@angular/core';
3
+
4
+ // Auto-injected into <head> by the tooltip directive on first use.
5
+ // This keeps the tooltip fully self-contained in ui-ng with zero
6
+ // external stylesheet dependencies.
7
+ const TOOLTIP_STYLES = `
8
+ .fk-tooltip {
9
+ position: fixed;
10
+ z-index: var(--fk-tooltip-z-index, 1100);
11
+ max-width: var(--fk-tooltip-max-width, 20rem);
12
+ padding: var(--fk-tooltip-padding, var(--fk-rhythm-1, 0.25rem) var(--fk-rhythm-2, 0.5rem));
13
+ border-radius: var(--fk-tooltip-border-radius, var(--fk-radius-sm, 0.25rem));
14
+ background-color: var(--fk-tooltip-bg, var(--fk-color-text, #1f2d3d));
15
+ color: var(--fk-tooltip-color, var(--fk-color-surface, #ffffff));
16
+ font-family: var(--fk-tooltip-font-family, var(--fk-font-family-base, sans-serif));
17
+ font-size: var(--fk-tooltip-font-size, var(--fk-typography-caption-font-size, 0.75rem));
18
+ font-weight: var(--fk-tooltip-font-weight, var(--fk-font-weight-medium, 500));
19
+ line-height: var(--fk-tooltip-line-height, var(--fk-typography-caption-line-height, 1.3));
20
+ box-shadow: var(--fk-tooltip-shadow, 0 2px 8px rgba(0, 0, 0, 0.15));
21
+ pointer-events: none;
22
+ white-space: normal;
23
+ word-wrap: break-word;
24
+ opacity: 0;
25
+ transform: scale(0.96);
26
+ transition:
27
+ opacity var(--fk-tooltip-enter-duration, 0.15s) var(--fk-tooltip-easing, ease-out),
28
+ transform var(--fk-tooltip-enter-duration, 0.15s) var(--fk-tooltip-easing, ease-out);
29
+ }
30
+ .fk-tooltip--visible {
31
+ opacity: 1;
32
+ transform: scale(1);
33
+ }
34
+ .fk-tooltip--hiding {
35
+ opacity: 0;
36
+ transform: scale(0.96);
37
+ transition-duration: var(--fk-tooltip-exit-duration, 0.1s);
38
+ }
39
+ .fk-tooltip__text {
40
+ display: block;
41
+ }
42
+ .fk-tooltip__arrow {
43
+ position: absolute;
44
+ width: 0;
45
+ height: 0;
46
+ border-style: solid;
47
+ }
48
+ .fk-tooltip--top .fk-tooltip__arrow {
49
+ bottom: calc(-1 * var(--fk-tooltip-arrow-size, 6px));
50
+ left: var(--fk-tooltip-arrow-offset, 50%);
51
+ transform: translateX(-50%);
52
+ border-width: var(--fk-tooltip-arrow-size, 6px) var(--fk-tooltip-arrow-size, 6px) 0;
53
+ border-color: var(--fk-tooltip-bg, var(--fk-color-text, #1f2d3d)) transparent transparent;
54
+ }
55
+ .fk-tooltip--bottom .fk-tooltip__arrow {
56
+ top: calc(-1 * var(--fk-tooltip-arrow-size, 6px));
57
+ left: var(--fk-tooltip-arrow-offset, 50%);
58
+ transform: translateX(-50%);
59
+ border-width: 0 var(--fk-tooltip-arrow-size, 6px) var(--fk-tooltip-arrow-size, 6px);
60
+ border-color: transparent transparent var(--fk-tooltip-bg, var(--fk-color-text, #1f2d3d));
61
+ }
62
+ .fk-tooltip--left .fk-tooltip__arrow {
63
+ right: calc(-1 * var(--fk-tooltip-arrow-size, 6px));
64
+ top: var(--fk-tooltip-arrow-offset, 50%);
65
+ transform: translateY(-50%);
66
+ border-width: var(--fk-tooltip-arrow-size, 6px) 0 var(--fk-tooltip-arrow-size, 6px) var(--fk-tooltip-arrow-size, 6px);
67
+ border-color: transparent transparent transparent var(--fk-tooltip-bg, var(--fk-color-text, #1f2d3d));
68
+ }
69
+ .fk-tooltip--right .fk-tooltip__arrow {
70
+ left: calc(-1 * var(--fk-tooltip-arrow-size, 6px));
71
+ top: var(--fk-tooltip-arrow-offset, 50%);
72
+ transform: translateY(-50%);
73
+ border-width: var(--fk-tooltip-arrow-size, 6px) var(--fk-tooltip-arrow-size, 6px) var(--fk-tooltip-arrow-size, 6px) 0;
74
+ border-color: transparent var(--fk-tooltip-bg, var(--fk-color-text, #1f2d3d)) transparent transparent;
75
+ }
76
+ @media (prefers-reduced-motion: reduce) {
77
+ .fk-tooltip {
78
+ transition: none;
79
+ }
80
+ }
81
+ `;
82
+ const STYLE_ID = 'fk-tooltip-styles';
83
+ let injected = false;
84
+ function injectTooltipStyles() {
85
+ if (injected || typeof document === 'undefined') {
86
+ return;
87
+ }
88
+ if (document.getElementById(STYLE_ID)) {
89
+ injected = true;
90
+ return;
91
+ }
92
+ const style = document.createElement('style');
93
+ style.id = STYLE_ID;
94
+ style.textContent = TOOLTIP_STYLES;
95
+ document.head.appendChild(style);
96
+ injected = true;
97
+ }
98
+
99
+ const VIEWPORT_PADDING = 8;
100
+ function computeTooltipPosition(anchorRect, tooltipWidth, tooltipHeight, preferred, offset, viewport) {
101
+ const positions = getPositionCandidates(preferred);
102
+ for (const position of positions) {
103
+ const result = tryPosition(anchorRect, tooltipWidth, tooltipHeight, position, offset);
104
+ if (fitsViewport(result, tooltipWidth, tooltipHeight, viewport)) {
105
+ return applyShift(result, tooltipWidth, tooltipHeight, viewport);
106
+ }
107
+ }
108
+ return applyShift(tryPosition(anchorRect, tooltipWidth, tooltipHeight, preferred, offset), tooltipWidth, tooltipHeight, viewport);
109
+ }
110
+ function getPositionCandidates(preferred) {
111
+ const opposites = {
112
+ top: 'bottom',
113
+ bottom: 'top',
114
+ left: 'right',
115
+ right: 'left',
116
+ };
117
+ return [preferred, opposites[preferred]];
118
+ }
119
+ function tryPosition(anchor, tooltipWidth, tooltipHeight, position, offset) {
120
+ const anchorCenterX = anchor.left + anchor.width / 2;
121
+ const anchorCenterY = anchor.top + anchor.height / 2;
122
+ let x;
123
+ let y;
124
+ switch (position) {
125
+ case 'top':
126
+ x = anchorCenterX - tooltipWidth / 2;
127
+ y = anchor.top - tooltipHeight - offset;
128
+ break;
129
+ case 'bottom':
130
+ x = anchorCenterX - tooltipWidth / 2;
131
+ y = anchor.bottom + offset;
132
+ break;
133
+ case 'left':
134
+ x = anchor.left - tooltipWidth - offset;
135
+ y = anchorCenterY - tooltipHeight / 2;
136
+ break;
137
+ case 'right':
138
+ x = anchor.right + offset;
139
+ y = anchorCenterY - tooltipHeight / 2;
140
+ break;
141
+ }
142
+ return {
143
+ x,
144
+ y,
145
+ actualPosition: position,
146
+ arrowOffset: 50,
147
+ };
148
+ }
149
+ function fitsViewport(result, tooltipWidth, tooltipHeight, viewport) {
150
+ return (result.x >= VIEWPORT_PADDING &&
151
+ result.y >= VIEWPORT_PADDING &&
152
+ result.x + tooltipWidth <= viewport.width - VIEWPORT_PADDING &&
153
+ result.y + tooltipHeight <= viewport.height - VIEWPORT_PADDING);
154
+ }
155
+ function applyShift(result, tooltipWidth, tooltipHeight, viewport) {
156
+ let { x, y, arrowOffset } = result;
157
+ const originalX = x;
158
+ const originalY = y;
159
+ x = Math.max(VIEWPORT_PADDING, Math.min(x, viewport.width - tooltipWidth - VIEWPORT_PADDING));
160
+ y = Math.max(VIEWPORT_PADDING, Math.min(y, viewport.height - tooltipHeight - VIEWPORT_PADDING));
161
+ if (result.actualPosition === 'top' || result.actualPosition === 'bottom') {
162
+ const shiftX = x - originalX;
163
+ arrowOffset = Math.max(10, Math.min(90, 50 - (shiftX / tooltipWidth) * 100));
164
+ }
165
+ else {
166
+ const shiftY = y - originalY;
167
+ arrowOffset = Math.max(10, Math.min(90, 50 - (shiftY / tooltipHeight) * 100));
168
+ }
169
+ return { ...result, x, y, arrowOffset };
170
+ }
171
+
172
+ let nextId = 0;
173
+ class TooltipDirective {
174
+ /** Text content displayed inside the tooltip bubble. */
175
+ fkTooltip = input.required(...(ngDevMode ? [{ debugName: "fkTooltip" }] : /* istanbul ignore next */ []));
176
+ /** Preferred position of the tooltip relative to the anchor element. */
177
+ fkTooltipPosition = input('top', ...(ngDevMode ? [{ debugName: "fkTooltipPosition" }] : /* istanbul ignore next */ []));
178
+ /** Gap in pixels between the anchor element and the tooltip bubble. */
179
+ fkTooltipOffset = input(8, ...(ngDevMode ? [{ debugName: "fkTooltipOffset" }] : /* istanbul ignore next */ []));
180
+ /** Delay in milliseconds before the tooltip appears after the trigger event. */
181
+ fkTooltipShowDelay = input(200, ...(ngDevMode ? [{ debugName: "fkTooltipShowDelay" }] : /* istanbul ignore next */ []));
182
+ /** Delay in milliseconds before the tooltip hides after the leave event. */
183
+ fkTooltipHideDelay = input(0, ...(ngDevMode ? [{ debugName: "fkTooltipHideDelay" }] : /* istanbul ignore next */ []));
184
+ /** When true, suppresses all tooltip display entirely. */
185
+ fkTooltipDisabled = input(false, ...(ngDevMode ? [{ debugName: "fkTooltipDisabled" }] : /* istanbul ignore next */ []));
186
+ /** Additional CSS class names applied to the tooltip root element. */
187
+ fkTooltipClassName = input('', ...(ngDevMode ? [{ debugName: "fkTooltipClassName" }] : /* istanbul ignore next */ []));
188
+ elRef = inject((ElementRef));
189
+ renderer = inject(Renderer2);
190
+ ngZone = inject(NgZone);
191
+ destroyRef = inject(DestroyRef);
192
+ tooltipEl = null;
193
+ tooltipId = '';
194
+ showTimeout = null;
195
+ hideTimeout = null;
196
+ scrollListeners = [];
197
+ resizeListener = null;
198
+ escapeListener = null;
199
+ visible = false;
200
+ constructor() {
201
+ injectTooltipStyles();
202
+ this.ngZone.runOutsideAngular(() => {
203
+ const el = this.elRef.nativeElement;
204
+ el.addEventListener('mouseenter', this.onMouseEnter);
205
+ el.addEventListener('mouseleave', this.onMouseLeave);
206
+ el.addEventListener('focusin', this.onFocusIn);
207
+ el.addEventListener('focusout', this.onFocusOut);
208
+ el.addEventListener('touchstart', this.onTouchStart, { passive: true });
209
+ });
210
+ effect(() => {
211
+ const text = this.fkTooltip();
212
+ if (this.tooltipEl) {
213
+ const textNode = this.tooltipEl.querySelector('.fk-tooltip__text');
214
+ if (textNode) {
215
+ textNode.textContent = text;
216
+ }
217
+ }
218
+ });
219
+ this.destroyRef.onDestroy(() => {
220
+ const el = this.elRef.nativeElement;
221
+ el.removeEventListener('mouseenter', this.onMouseEnter);
222
+ el.removeEventListener('mouseleave', this.onMouseLeave);
223
+ el.removeEventListener('focusin', this.onFocusIn);
224
+ el.removeEventListener('focusout', this.onFocusOut);
225
+ el.removeEventListener('touchstart', this.onTouchStart);
226
+ this.forceHide();
227
+ });
228
+ }
229
+ // ===== EVENT HANDLERS =====
230
+ onMouseEnter = () => {
231
+ this.scheduleShow();
232
+ };
233
+ onMouseLeave = () => {
234
+ this.scheduleHide();
235
+ };
236
+ onFocusIn = () => {
237
+ this.scheduleShow();
238
+ };
239
+ onFocusOut = () => {
240
+ this.scheduleHide();
241
+ };
242
+ onTouchStart = () => {
243
+ if (this.visible) {
244
+ this.scheduleHide();
245
+ }
246
+ else {
247
+ this.scheduleShow();
248
+ setTimeout(() => this.scheduleHide(), 1500);
249
+ }
250
+ };
251
+ onEscape = (event) => {
252
+ if (event.key === 'Escape') {
253
+ this.forceHide();
254
+ }
255
+ };
256
+ // ===== SHOW / HIDE =====
257
+ scheduleShow() {
258
+ if (this.fkTooltipDisabled() || !this.fkTooltip()) {
259
+ return;
260
+ }
261
+ this.clearTimeouts();
262
+ this.showTimeout = setTimeout(() => {
263
+ this.show();
264
+ }, this.fkTooltipShowDelay());
265
+ }
266
+ scheduleHide() {
267
+ this.clearTimeouts();
268
+ this.hideTimeout = setTimeout(() => {
269
+ this.hide();
270
+ }, this.fkTooltipHideDelay());
271
+ }
272
+ show() {
273
+ if (this.visible) {
274
+ return;
275
+ }
276
+ this.visible = true;
277
+ this.createTooltipElement();
278
+ this.updatePosition();
279
+ this.attachPositionListeners();
280
+ requestAnimationFrame(() => {
281
+ this.tooltipEl?.classList.add('fk-tooltip--visible');
282
+ });
283
+ }
284
+ hide() {
285
+ if (!this.visible || !this.tooltipEl) {
286
+ return;
287
+ }
288
+ this.visible = false;
289
+ this.tooltipEl.classList.remove('fk-tooltip--visible');
290
+ this.tooltipEl.classList.add('fk-tooltip--hiding');
291
+ const el = this.tooltipEl;
292
+ const cleanup = () => {
293
+ el.removeEventListener('transitionend', onTransitionEnd);
294
+ clearTimeout(fallback);
295
+ this.removeTooltipElement();
296
+ };
297
+ const onTransitionEnd = () => cleanup();
298
+ const fallback = setTimeout(() => cleanup(), 200);
299
+ el.addEventListener('transitionend', onTransitionEnd, { once: true });
300
+ }
301
+ forceHide() {
302
+ this.clearTimeouts();
303
+ this.visible = false;
304
+ this.removeTooltipElement();
305
+ }
306
+ // ===== DOM CREATION =====
307
+ createTooltipElement() {
308
+ if (this.tooltipEl) {
309
+ return;
310
+ }
311
+ this.tooltipId = `fk-tooltip-${nextId++}`;
312
+ const tooltip = this.renderer.createElement('div');
313
+ tooltip.className = this.buildTooltipClasses();
314
+ tooltip.setAttribute('role', 'tooltip');
315
+ tooltip.setAttribute('id', this.tooltipId);
316
+ const textSpan = this.renderer.createElement('span');
317
+ textSpan.className = 'fk-tooltip__text';
318
+ textSpan.textContent = this.fkTooltip();
319
+ tooltip.appendChild(textSpan);
320
+ const arrow = this.renderer.createElement('div');
321
+ arrow.className = 'fk-tooltip__arrow';
322
+ tooltip.appendChild(arrow);
323
+ this.tooltipEl = tooltip;
324
+ document.body.appendChild(tooltip);
325
+ this.elRef.nativeElement.setAttribute('aria-describedby', this.tooltipId);
326
+ this.escapeListener = this.renderer.listen('document', 'keydown', this.onEscape);
327
+ }
328
+ removeTooltipElement() {
329
+ if (this.tooltipEl) {
330
+ this.tooltipEl.remove();
331
+ this.tooltipEl = null;
332
+ }
333
+ this.elRef.nativeElement.removeAttribute('aria-describedby');
334
+ this.detachPositionListeners();
335
+ if (this.escapeListener) {
336
+ this.escapeListener();
337
+ this.escapeListener = null;
338
+ }
339
+ }
340
+ buildTooltipClasses() {
341
+ return [
342
+ 'fk-tooltip',
343
+ `fk-tooltip--${this.fkTooltipPosition()}`,
344
+ this.fkTooltipClassName(),
345
+ ]
346
+ .filter(Boolean)
347
+ .join(' ');
348
+ }
349
+ // ===== POSITIONING =====
350
+ updatePosition() {
351
+ if (!this.tooltipEl) {
352
+ return;
353
+ }
354
+ const anchorRect = this.elRef.nativeElement.getBoundingClientRect();
355
+ const tooltipRect = this.tooltipEl.getBoundingClientRect();
356
+ const result = computeTooltipPosition(anchorRect, tooltipRect.width, tooltipRect.height, this.fkTooltipPosition(), this.fkTooltipOffset(), { width: window.innerWidth, height: window.innerHeight });
357
+ this.tooltipEl.style.left = `${result.x}px`;
358
+ this.tooltipEl.style.top = `${result.y}px`;
359
+ this.tooltipEl.style.setProperty('--fk-tooltip-arrow-offset', `${result.arrowOffset}%`);
360
+ const actualClass = `fk-tooltip--${result.actualPosition}`;
361
+ const preferredClass = `fk-tooltip--${this.fkTooltipPosition()}`;
362
+ if (actualClass !== preferredClass) {
363
+ this.tooltipEl.classList.remove(preferredClass);
364
+ this.tooltipEl.classList.add(actualClass);
365
+ }
366
+ }
367
+ attachPositionListeners() {
368
+ this.ngZone.runOutsideAngular(() => {
369
+ const updatePos = () => {
370
+ if (this.visible) {
371
+ this.updatePosition();
372
+ }
373
+ };
374
+ this.resizeListener = this.renderer.listen('window', 'resize', updatePos);
375
+ let ancestor = this.elRef.nativeElement.parentElement;
376
+ while (ancestor) {
377
+ if (ancestor.scrollHeight > ancestor.clientHeight ||
378
+ ancestor.scrollWidth > ancestor.clientWidth) {
379
+ const el = ancestor;
380
+ const handler = () => updatePos();
381
+ el.addEventListener('scroll', handler, { passive: true });
382
+ this.scrollListeners.push(() => el.removeEventListener('scroll', handler));
383
+ }
384
+ ancestor = ancestor.parentElement;
385
+ }
386
+ });
387
+ }
388
+ detachPositionListeners() {
389
+ if (this.resizeListener) {
390
+ this.resizeListener();
391
+ this.resizeListener = null;
392
+ }
393
+ for (const unsub of this.scrollListeners) {
394
+ unsub();
395
+ }
396
+ this.scrollListeners = [];
397
+ }
398
+ // ===== HELPERS =====
399
+ clearTimeouts() {
400
+ if (this.showTimeout) {
401
+ clearTimeout(this.showTimeout);
402
+ this.showTimeout = null;
403
+ }
404
+ if (this.hideTimeout) {
405
+ clearTimeout(this.hideTimeout);
406
+ this.hideTimeout = null;
407
+ }
408
+ }
409
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: TooltipDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive });
410
+ static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "21.2.9", type: TooltipDirective, isStandalone: true, selector: "[fkTooltip]", inputs: { fkTooltip: { classPropertyName: "fkTooltip", publicName: "fkTooltip", isSignal: true, isRequired: true, transformFunction: null }, fkTooltipPosition: { classPropertyName: "fkTooltipPosition", publicName: "fkTooltipPosition", isSignal: true, isRequired: false, transformFunction: null }, fkTooltipOffset: { classPropertyName: "fkTooltipOffset", publicName: "fkTooltipOffset", isSignal: true, isRequired: false, transformFunction: null }, fkTooltipShowDelay: { classPropertyName: "fkTooltipShowDelay", publicName: "fkTooltipShowDelay", isSignal: true, isRequired: false, transformFunction: null }, fkTooltipHideDelay: { classPropertyName: "fkTooltipHideDelay", publicName: "fkTooltipHideDelay", isSignal: true, isRequired: false, transformFunction: null }, fkTooltipDisabled: { classPropertyName: "fkTooltipDisabled", publicName: "fkTooltipDisabled", isSignal: true, isRequired: false, transformFunction: null }, fkTooltipClassName: { classPropertyName: "fkTooltipClassName", publicName: "fkTooltipClassName", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0 });
411
+ }
412
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: TooltipDirective, decorators: [{
413
+ type: Directive,
414
+ args: [{
415
+ selector: '[fkTooltip]',
416
+ standalone: true,
417
+ }]
418
+ }], ctorParameters: () => [], propDecorators: { fkTooltip: [{ type: i0.Input, args: [{ isSignal: true, alias: "fkTooltip", required: true }] }], fkTooltipPosition: [{ type: i0.Input, args: [{ isSignal: true, alias: "fkTooltipPosition", required: false }] }], fkTooltipOffset: [{ type: i0.Input, args: [{ isSignal: true, alias: "fkTooltipOffset", required: false }] }], fkTooltipShowDelay: [{ type: i0.Input, args: [{ isSignal: true, alias: "fkTooltipShowDelay", required: false }] }], fkTooltipHideDelay: [{ type: i0.Input, args: [{ isSignal: true, alias: "fkTooltipHideDelay", required: false }] }], fkTooltipDisabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "fkTooltipDisabled", required: false }] }], fkTooltipClassName: [{ type: i0.Input, args: [{ isSignal: true, alias: "fkTooltipClassName", required: false }] }] } });
419
+
420
+ /**
421
+ * Generated bundle index. Do not edit.
422
+ */
423
+
424
+ export { TOOLTIP_STYLES, TooltipDirective, computeTooltipPosition, injectTooltipStyles };
425
+ //# sourceMappingURL=frame-kit-ui-ng-directives-tooltip.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"frame-kit-ui-ng-directives-tooltip.mjs","sources":["../../../../packages/ui-ng/directives/tooltip/tooltip.styles.ts","../../../../packages/ui-ng/directives/tooltip/tooltip-position.util.ts","../../../../packages/ui-ng/directives/tooltip/tooltip.directive.ts","../../../../packages/ui-ng/directives/tooltip/frame-kit-ui-ng-directives-tooltip.ts"],"sourcesContent":["// Auto-injected into <head> by the tooltip directive on first use.\n// This keeps the tooltip fully self-contained in ui-ng with zero\n// external stylesheet dependencies.\n\nexport const TOOLTIP_STYLES = `\n.fk-tooltip {\n position: fixed;\n z-index: var(--fk-tooltip-z-index, 1100);\n max-width: var(--fk-tooltip-max-width, 20rem);\n padding: var(--fk-tooltip-padding, var(--fk-rhythm-1, 0.25rem) var(--fk-rhythm-2, 0.5rem));\n border-radius: var(--fk-tooltip-border-radius, var(--fk-radius-sm, 0.25rem));\n background-color: var(--fk-tooltip-bg, var(--fk-color-text, #1f2d3d));\n color: var(--fk-tooltip-color, var(--fk-color-surface, #ffffff));\n font-family: var(--fk-tooltip-font-family, var(--fk-font-family-base, sans-serif));\n font-size: var(--fk-tooltip-font-size, var(--fk-typography-caption-font-size, 0.75rem));\n font-weight: var(--fk-tooltip-font-weight, var(--fk-font-weight-medium, 500));\n line-height: var(--fk-tooltip-line-height, var(--fk-typography-caption-line-height, 1.3));\n box-shadow: var(--fk-tooltip-shadow, 0 2px 8px rgba(0, 0, 0, 0.15));\n pointer-events: none;\n white-space: normal;\n word-wrap: break-word;\n opacity: 0;\n transform: scale(0.96);\n transition:\n opacity var(--fk-tooltip-enter-duration, 0.15s) var(--fk-tooltip-easing, ease-out),\n transform var(--fk-tooltip-enter-duration, 0.15s) var(--fk-tooltip-easing, ease-out);\n}\n.fk-tooltip--visible {\n opacity: 1;\n transform: scale(1);\n}\n.fk-tooltip--hiding {\n opacity: 0;\n transform: scale(0.96);\n transition-duration: var(--fk-tooltip-exit-duration, 0.1s);\n}\n.fk-tooltip__text {\n display: block;\n}\n.fk-tooltip__arrow {\n position: absolute;\n width: 0;\n height: 0;\n border-style: solid;\n}\n.fk-tooltip--top .fk-tooltip__arrow {\n bottom: calc(-1 * var(--fk-tooltip-arrow-size, 6px));\n left: var(--fk-tooltip-arrow-offset, 50%);\n transform: translateX(-50%);\n border-width: var(--fk-tooltip-arrow-size, 6px) var(--fk-tooltip-arrow-size, 6px) 0;\n border-color: var(--fk-tooltip-bg, var(--fk-color-text, #1f2d3d)) transparent transparent;\n}\n.fk-tooltip--bottom .fk-tooltip__arrow {\n top: calc(-1 * var(--fk-tooltip-arrow-size, 6px));\n left: var(--fk-tooltip-arrow-offset, 50%);\n transform: translateX(-50%);\n border-width: 0 var(--fk-tooltip-arrow-size, 6px) var(--fk-tooltip-arrow-size, 6px);\n border-color: transparent transparent var(--fk-tooltip-bg, var(--fk-color-text, #1f2d3d));\n}\n.fk-tooltip--left .fk-tooltip__arrow {\n right: calc(-1 * var(--fk-tooltip-arrow-size, 6px));\n top: var(--fk-tooltip-arrow-offset, 50%);\n transform: translateY(-50%);\n border-width: var(--fk-tooltip-arrow-size, 6px) 0 var(--fk-tooltip-arrow-size, 6px) var(--fk-tooltip-arrow-size, 6px);\n border-color: transparent transparent transparent var(--fk-tooltip-bg, var(--fk-color-text, #1f2d3d));\n}\n.fk-tooltip--right .fk-tooltip__arrow {\n left: calc(-1 * var(--fk-tooltip-arrow-size, 6px));\n top: var(--fk-tooltip-arrow-offset, 50%);\n transform: translateY(-50%);\n border-width: var(--fk-tooltip-arrow-size, 6px) var(--fk-tooltip-arrow-size, 6px) var(--fk-tooltip-arrow-size, 6px) 0;\n border-color: transparent var(--fk-tooltip-bg, var(--fk-color-text, #1f2d3d)) transparent transparent;\n}\n@media (prefers-reduced-motion: reduce) {\n .fk-tooltip {\n transition: none;\n }\n}\n`;\n\nconst STYLE_ID = 'fk-tooltip-styles';\nlet injected = false;\n\nexport function injectTooltipStyles(): void {\n if (injected || typeof document === 'undefined') {\n return;\n }\n\n if (document.getElementById(STYLE_ID)) {\n injected = true;\n\n return;\n }\n\n const style = document.createElement('style');\n\n style.id = STYLE_ID;\n style.textContent = TOOLTIP_STYLES;\n document.head.appendChild(style);\n injected = true;\n}\n","import type { TooltipPosition } from './tooltip.types';\n\nexport interface PositionResult {\n x: number;\n y: number;\n actualPosition: TooltipPosition;\n arrowOffset: number;\n}\n\nconst VIEWPORT_PADDING = 8;\n\nexport function computeTooltipPosition(\n anchorRect: DOMRect,\n tooltipWidth: number,\n tooltipHeight: number,\n preferred: TooltipPosition,\n offset: number,\n viewport: { width: number; height: number },\n): PositionResult {\n const positions = getPositionCandidates(preferred);\n\n for (const position of positions) {\n const result = tryPosition(\n anchorRect,\n tooltipWidth,\n tooltipHeight,\n position,\n offset,\n );\n\n if (fitsViewport(result, tooltipWidth, tooltipHeight, viewport)) {\n return applyShift(result, tooltipWidth, tooltipHeight, viewport);\n }\n }\n\n return applyShift(\n tryPosition(anchorRect, tooltipWidth, tooltipHeight, preferred, offset),\n tooltipWidth,\n tooltipHeight,\n viewport,\n );\n}\n\nfunction getPositionCandidates(preferred: TooltipPosition): TooltipPosition[] {\n const opposites: Record<TooltipPosition, TooltipPosition> = {\n top: 'bottom',\n bottom: 'top',\n left: 'right',\n right: 'left',\n };\n\n return [preferred, opposites[preferred]];\n}\n\nfunction tryPosition(\n anchor: DOMRect,\n tooltipWidth: number,\n tooltipHeight: number,\n position: TooltipPosition,\n offset: number,\n): PositionResult {\n const anchorCenterX = anchor.left + anchor.width / 2;\n const anchorCenterY = anchor.top + anchor.height / 2;\n\n let x: number;\n let y: number;\n\n switch (position) {\n case 'top':\n x = anchorCenterX - tooltipWidth / 2;\n y = anchor.top - tooltipHeight - offset;\n break;\n case 'bottom':\n x = anchorCenterX - tooltipWidth / 2;\n y = anchor.bottom + offset;\n break;\n case 'left':\n x = anchor.left - tooltipWidth - offset;\n y = anchorCenterY - tooltipHeight / 2;\n break;\n case 'right':\n x = anchor.right + offset;\n y = anchorCenterY - tooltipHeight / 2;\n break;\n }\n\n return {\n x,\n y,\n actualPosition: position,\n arrowOffset: 50,\n };\n}\n\nfunction fitsViewport(\n result: PositionResult,\n tooltipWidth: number,\n tooltipHeight: number,\n viewport: { width: number; height: number },\n): boolean {\n return (\n result.x >= VIEWPORT_PADDING &&\n result.y >= VIEWPORT_PADDING &&\n result.x + tooltipWidth <= viewport.width - VIEWPORT_PADDING &&\n result.y + tooltipHeight <= viewport.height - VIEWPORT_PADDING\n );\n}\n\nfunction applyShift(\n result: PositionResult,\n tooltipWidth: number,\n tooltipHeight: number,\n viewport: { width: number; height: number },\n): PositionResult {\n let { x, y, arrowOffset } = result;\n\n const originalX = x;\n const originalY = y;\n\n x = Math.max(\n VIEWPORT_PADDING,\n Math.min(x, viewport.width - tooltipWidth - VIEWPORT_PADDING),\n );\n y = Math.max(\n VIEWPORT_PADDING,\n Math.min(y, viewport.height - tooltipHeight - VIEWPORT_PADDING),\n );\n\n if (result.actualPosition === 'top' || result.actualPosition === 'bottom') {\n const shiftX = x - originalX;\n\n arrowOffset = Math.max(\n 10,\n Math.min(90, 50 - (shiftX / tooltipWidth) * 100),\n );\n } else {\n const shiftY = y - originalY;\n\n arrowOffset = Math.max(\n 10,\n Math.min(90, 50 - (shiftY / tooltipHeight) * 100),\n );\n }\n\n return { ...result, x, y, arrowOffset };\n}\n","import {\n DestroyRef,\n Directive,\n effect,\n ElementRef,\n inject,\n input,\n NgZone,\n Renderer2,\n} from '@angular/core';\n\nimport { injectTooltipStyles } from './tooltip.styles';\nimport type { TooltipPosition } from './tooltip.types';\nimport { computeTooltipPosition } from './tooltip-position.util';\n\nlet nextId = 0;\n\n@Directive({\n selector: '[fkTooltip]',\n standalone: true,\n})\nexport class TooltipDirective {\n /** Text content displayed inside the tooltip bubble. */\n readonly fkTooltip = input.required<string>();\n /** Preferred position of the tooltip relative to the anchor element. */\n readonly fkTooltipPosition = input<TooltipPosition>('top');\n /** Gap in pixels between the anchor element and the tooltip bubble. */\n readonly fkTooltipOffset = input<number>(8);\n /** Delay in milliseconds before the tooltip appears after the trigger event. */\n readonly fkTooltipShowDelay = input<number>(200);\n /** Delay in milliseconds before the tooltip hides after the leave event. */\n readonly fkTooltipHideDelay = input<number>(0);\n /** When true, suppresses all tooltip display entirely. */\n readonly fkTooltipDisabled = input<boolean>(false);\n /** Additional CSS class names applied to the tooltip root element. */\n readonly fkTooltipClassName = input<string>('');\n\n private readonly elRef = inject(ElementRef<HTMLElement>);\n private readonly renderer = inject(Renderer2);\n private readonly ngZone = inject(NgZone);\n private readonly destroyRef = inject(DestroyRef);\n\n private tooltipEl: HTMLElement | null = null;\n private tooltipId = '';\n private showTimeout: ReturnType<typeof setTimeout> | null = null;\n private hideTimeout: ReturnType<typeof setTimeout> | null = null;\n private scrollListeners: (() => void)[] = [];\n private resizeListener: (() => void) | null = null;\n private escapeListener: (() => void) | null = null;\n private visible = false;\n\n constructor() {\n injectTooltipStyles();\n\n this.ngZone.runOutsideAngular(() => {\n const el = this.elRef.nativeElement;\n\n el.addEventListener('mouseenter', this.onMouseEnter);\n el.addEventListener('mouseleave', this.onMouseLeave);\n el.addEventListener('focusin', this.onFocusIn);\n el.addEventListener('focusout', this.onFocusOut);\n el.addEventListener('touchstart', this.onTouchStart, { passive: true });\n });\n\n effect(() => {\n const text = this.fkTooltip();\n\n if (this.tooltipEl) {\n const textNode = this.tooltipEl.querySelector('.fk-tooltip__text');\n\n if (textNode) {\n textNode.textContent = text;\n }\n }\n });\n\n this.destroyRef.onDestroy(() => {\n const el = this.elRef.nativeElement;\n\n el.removeEventListener('mouseenter', this.onMouseEnter);\n el.removeEventListener('mouseleave', this.onMouseLeave);\n el.removeEventListener('focusin', this.onFocusIn);\n el.removeEventListener('focusout', this.onFocusOut);\n el.removeEventListener('touchstart', this.onTouchStart);\n this.forceHide();\n });\n }\n\n // ===== EVENT HANDLERS =====\n\n private readonly onMouseEnter = (): void => {\n this.scheduleShow();\n };\n\n private readonly onMouseLeave = (): void => {\n this.scheduleHide();\n };\n\n private readonly onFocusIn = (): void => {\n this.scheduleShow();\n };\n\n private readonly onFocusOut = (): void => {\n this.scheduleHide();\n };\n\n private readonly onTouchStart = (): void => {\n if (this.visible) {\n this.scheduleHide();\n } else {\n this.scheduleShow();\n setTimeout(() => this.scheduleHide(), 1500);\n }\n };\n\n private readonly onEscape = (event: KeyboardEvent): void => {\n if (event.key === 'Escape') {\n this.forceHide();\n }\n };\n\n // ===== SHOW / HIDE =====\n\n private scheduleShow(): void {\n if (this.fkTooltipDisabled() || !this.fkTooltip()) {\n return;\n }\n\n this.clearTimeouts();\n\n this.showTimeout = setTimeout(() => {\n this.show();\n }, this.fkTooltipShowDelay());\n }\n\n private scheduleHide(): void {\n this.clearTimeouts();\n\n this.hideTimeout = setTimeout(() => {\n this.hide();\n }, this.fkTooltipHideDelay());\n }\n\n private show(): void {\n if (this.visible) {\n return;\n }\n\n this.visible = true;\n this.createTooltipElement();\n this.updatePosition();\n this.attachPositionListeners();\n\n requestAnimationFrame(() => {\n this.tooltipEl?.classList.add('fk-tooltip--visible');\n });\n }\n\n private hide(): void {\n if (!this.visible || !this.tooltipEl) {\n return;\n }\n\n this.visible = false;\n this.tooltipEl.classList.remove('fk-tooltip--visible');\n this.tooltipEl.classList.add('fk-tooltip--hiding');\n\n const el = this.tooltipEl;\n\n const cleanup = () => {\n el.removeEventListener('transitionend', onTransitionEnd);\n clearTimeout(fallback);\n this.removeTooltipElement();\n };\n\n const onTransitionEnd = () => cleanup();\n\n const fallback = setTimeout(() => cleanup(), 200);\n\n el.addEventListener('transitionend', onTransitionEnd, { once: true });\n }\n\n private forceHide(): void {\n this.clearTimeouts();\n this.visible = false;\n this.removeTooltipElement();\n }\n\n // ===== DOM CREATION =====\n\n private createTooltipElement(): void {\n if (this.tooltipEl) {\n return;\n }\n\n this.tooltipId = `fk-tooltip-${nextId++}`;\n\n const tooltip = this.renderer.createElement('div') as HTMLElement;\n\n tooltip.className = this.buildTooltipClasses();\n tooltip.setAttribute('role', 'tooltip');\n tooltip.setAttribute('id', this.tooltipId);\n\n const textSpan = this.renderer.createElement('span') as HTMLElement;\n\n textSpan.className = 'fk-tooltip__text';\n textSpan.textContent = this.fkTooltip();\n tooltip.appendChild(textSpan);\n\n const arrow = this.renderer.createElement('div') as HTMLElement;\n\n arrow.className = 'fk-tooltip__arrow';\n tooltip.appendChild(arrow);\n\n this.tooltipEl = tooltip;\n\n document.body.appendChild(tooltip);\n this.elRef.nativeElement.setAttribute('aria-describedby', this.tooltipId);\n\n this.escapeListener = this.renderer.listen(\n 'document',\n 'keydown',\n this.onEscape,\n );\n }\n\n private removeTooltipElement(): void {\n if (this.tooltipEl) {\n this.tooltipEl.remove();\n this.tooltipEl = null;\n }\n\n this.elRef.nativeElement.removeAttribute('aria-describedby');\n this.detachPositionListeners();\n\n if (this.escapeListener) {\n this.escapeListener();\n this.escapeListener = null;\n }\n }\n\n private buildTooltipClasses(): string {\n return [\n 'fk-tooltip',\n `fk-tooltip--${this.fkTooltipPosition()}`,\n this.fkTooltipClassName(),\n ]\n .filter(Boolean)\n .join(' ');\n }\n\n // ===== POSITIONING =====\n\n private updatePosition(): void {\n if (!this.tooltipEl) {\n return;\n }\n\n const anchorRect = this.elRef.nativeElement.getBoundingClientRect();\n const tooltipRect = this.tooltipEl.getBoundingClientRect();\n\n const result = computeTooltipPosition(\n anchorRect,\n tooltipRect.width,\n tooltipRect.height,\n this.fkTooltipPosition(),\n this.fkTooltipOffset(),\n { width: window.innerWidth, height: window.innerHeight },\n );\n\n this.tooltipEl.style.left = `${result.x}px`;\n this.tooltipEl.style.top = `${result.y}px`;\n this.tooltipEl.style.setProperty(\n '--fk-tooltip-arrow-offset',\n `${result.arrowOffset}%`,\n );\n\n const actualClass = `fk-tooltip--${result.actualPosition}`;\n const preferredClass = `fk-tooltip--${this.fkTooltipPosition()}`;\n\n if (actualClass !== preferredClass) {\n this.tooltipEl.classList.remove(preferredClass);\n this.tooltipEl.classList.add(actualClass);\n }\n }\n\n private attachPositionListeners(): void {\n this.ngZone.runOutsideAngular(() => {\n const updatePos = () => {\n if (this.visible) {\n this.updatePosition();\n }\n };\n\n this.resizeListener = this.renderer.listen('window', 'resize', updatePos);\n\n let ancestor: Element | null = this.elRef.nativeElement.parentElement;\n\n while (ancestor) {\n if (\n ancestor.scrollHeight > ancestor.clientHeight ||\n ancestor.scrollWidth > ancestor.clientWidth\n ) {\n const el = ancestor;\n const handler = () => updatePos();\n\n el.addEventListener('scroll', handler, { passive: true });\n this.scrollListeners.push(() =>\n el.removeEventListener('scroll', handler),\n );\n }\n\n ancestor = ancestor.parentElement;\n }\n });\n }\n\n private detachPositionListeners(): void {\n if (this.resizeListener) {\n this.resizeListener();\n this.resizeListener = null;\n }\n\n for (const unsub of this.scrollListeners) {\n unsub();\n }\n\n this.scrollListeners = [];\n }\n\n // ===== HELPERS =====\n\n private clearTimeouts(): void {\n if (this.showTimeout) {\n clearTimeout(this.showTimeout);\n this.showTimeout = null;\n }\n\n if (this.hideTimeout) {\n clearTimeout(this.hideTimeout);\n this.hideTimeout = null;\n }\n }\n}\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './index';\n"],"names":[],"mappings":"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"}
@@ -0,0 +1,63 @@
1
+ import * as i0 from '@angular/core';
2
+ import { inject, input, computed, HostBinding, ChangeDetectionStrategy, Component } from '@angular/core';
3
+ import { RouterLink, RouterLinkActive } from '@angular/router';
4
+ import { AppShellComponent } from '@frame-kit/ui-ng/layouts/app-shell';
5
+ import { MethodBadgeComponent } from '@frame-kit/ui-ng/docs/method-badge';
6
+
7
+ /**
8
+ * Sidebar/list item for an API endpoint in developer documentation.
9
+ *
10
+ * Renders a leading `fk-method-badge` followed by the endpoint label as a
11
+ * single clickable router link. Used to list operations (e.g. "GET List
12
+ * permissions", "POST Create identity") in a documentation sidebar or any
13
+ * denser endpoint index.
14
+ *
15
+ * Active state is driven by `routerLinkActive`, matching the behavior of
16
+ * `fk-sidenav-link` so every router-aware nav item in the library resolves
17
+ * active state the same way.
18
+ *
19
+ * When rendered inside an `fk-app-shell`, clicks also call `dismissSidenav`
20
+ * on the ancestor shell — this closes the mobile overlay so the user lands
21
+ * directly on the selected endpoint. On desktop it's a no-op.
22
+ */
23
+ class EndpointLinkComponent {
24
+ shell = inject(AppShellComponent, { optional: true });
25
+ // ===== INPUTS =====
26
+ method = input.required(...(ngDevMode ? [{ debugName: "method" }] : /* istanbul ignore next */ []));
27
+ label = input.required(...(ngDevMode ? [{ debugName: "label" }] : /* istanbul ignore next */ []));
28
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
29
+ routerLink = input.required(...(ngDevMode ? [{ debugName: "routerLink" }] : /* istanbul ignore next */ []));
30
+ /**
31
+ * Whether to require an exact URL match for the active state. Defaults to
32
+ * false — each endpoint has a unique final path segment so prefix matching
33
+ * resolves to the same thing in practice.
34
+ */
35
+ exact = input(false, ...(ngDevMode ? [{ debugName: "exact" }] : /* istanbul ignore next */ []));
36
+ // ===== BASE PROPS =====
37
+ className = input('', ...(ngDevMode ? [{ debugName: "className" }] : /* istanbul ignore next */ []));
38
+ // ===== COMPUTED =====
39
+ classes = computed(() => ['fk-endpoint-link', this.className()].filter(Boolean).join(' '), ...(ngDevMode ? [{ debugName: "classes" }] : /* istanbul ignore next */ []));
40
+ activeOptions = computed(() => ({ exact: this.exact() }), ...(ngDevMode ? [{ debugName: "activeOptions" }] : /* istanbul ignore next */ []));
41
+ get hostClass() {
42
+ return this.classes();
43
+ }
44
+ dismiss() {
45
+ this.shell?.dismissSidenav();
46
+ }
47
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: EndpointLinkComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
48
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "21.2.9", type: EndpointLinkComponent, isStandalone: true, selector: "fk-endpoint-link", inputs: { method: { classPropertyName: "method", publicName: "method", isSignal: true, isRequired: true, transformFunction: null }, label: { classPropertyName: "label", publicName: "label", isSignal: true, isRequired: true, transformFunction: null }, routerLink: { classPropertyName: "routerLink", publicName: "routerLink", isSignal: true, isRequired: true, transformFunction: null }, exact: { classPropertyName: "exact", publicName: "exact", isSignal: true, isRequired: false, transformFunction: null }, className: { classPropertyName: "className", publicName: "className", isSignal: true, isRequired: false, transformFunction: null } }, host: { properties: { "class": "this.hostClass" } }, ngImport: i0, template: "<a\n class=\"fk-endpoint-link__anchor\"\n [routerLink]=\"routerLink()\"\n routerLinkActive=\"fk-endpoint-link__anchor--active\"\n [routerLinkActiveOptions]=\"activeOptions()\"\n (click)=\"$event.stopPropagation(); dismiss()\"\n>\n <fk-method-badge [method]=\"method()\" class=\"fk-endpoint-link__badge\" />\n <span class=\"fk-endpoint-link__label\">{{ label() }}</span>\n</a>\n", styles: [".fk-endpoint-link{display:block}.fk-endpoint-link__anchor{display:flex;align-items:center;gap:var(--fk-endpoint-link-gap, var(--fk-rhythm-2, .5rem));padding:var(--fk-endpoint-link-padding-block, var(--fk-rhythm-1, .25rem)) var(--fk-endpoint-link-padding-inline, var(--fk-rhythm-3, .75rem));border-radius:var(--fk-endpoint-link-radius, var(--fk-radius-md, .5rem));color:var(--fk-endpoint-link-color, var(--fk-color-text, #1f2d3d));font-size:var(--fk-endpoint-link-font-size, .875rem);line-height:1.4;text-decoration:none;transition:background-color .15s ease}.fk-endpoint-link__anchor:hover{background-color:var(--fk-endpoint-link-bg-hover, var(--fk-color-surface-muted, #f7f9fb))}.fk-endpoint-link__anchor:focus-visible{outline:none;box-shadow:var(--fk-endpoint-link-focus-ring, var(--fk-focus-ring, 0 0 0 3px rgba(10, 132, 255, .18)))}.fk-endpoint-link__anchor--active,.fk-endpoint-link__anchor--active:hover{background-color:var(--fk-endpoint-link-bg-active, var(--fk-color-primary-light, #dbeafe));color:var(--fk-endpoint-link-color-active, var(--fk-color-primary, #1e3a8a));font-weight:var(--fk-endpoint-link-font-weight-active, var(--fk-font-weight-semibold, 600))}.fk-endpoint-link__badge{flex-shrink:0}.fk-endpoint-link__label{flex:1;min-width:0;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}\n"], dependencies: [{ kind: "directive", type: RouterLink, selector: "[routerLink]", inputs: ["target", "queryParams", "fragment", "queryParamsHandling", "state", "info", "relativeTo", "preserveFragment", "skipLocationChange", "replaceUrl", "routerLink"] }, { kind: "directive", type: RouterLinkActive, selector: "[routerLinkActive]", inputs: ["routerLinkActiveOptions", "ariaCurrentWhenActive", "routerLinkActive"], outputs: ["isActiveChange"], exportAs: ["routerLinkActive"] }, { kind: "component", type: MethodBadgeComponent, selector: "fk-method-badge", inputs: ["method", "className", "id", "ariaLabel"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
49
+ }
50
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: EndpointLinkComponent, decorators: [{
51
+ type: Component,
52
+ args: [{ selector: 'fk-endpoint-link', standalone: true, imports: [RouterLink, RouterLinkActive, MethodBadgeComponent], changeDetection: ChangeDetectionStrategy.OnPush, template: "<a\n class=\"fk-endpoint-link__anchor\"\n [routerLink]=\"routerLink()\"\n routerLinkActive=\"fk-endpoint-link__anchor--active\"\n [routerLinkActiveOptions]=\"activeOptions()\"\n (click)=\"$event.stopPropagation(); dismiss()\"\n>\n <fk-method-badge [method]=\"method()\" class=\"fk-endpoint-link__badge\" />\n <span class=\"fk-endpoint-link__label\">{{ label() }}</span>\n</a>\n", styles: [".fk-endpoint-link{display:block}.fk-endpoint-link__anchor{display:flex;align-items:center;gap:var(--fk-endpoint-link-gap, var(--fk-rhythm-2, .5rem));padding:var(--fk-endpoint-link-padding-block, var(--fk-rhythm-1, .25rem)) var(--fk-endpoint-link-padding-inline, var(--fk-rhythm-3, .75rem));border-radius:var(--fk-endpoint-link-radius, var(--fk-radius-md, .5rem));color:var(--fk-endpoint-link-color, var(--fk-color-text, #1f2d3d));font-size:var(--fk-endpoint-link-font-size, .875rem);line-height:1.4;text-decoration:none;transition:background-color .15s ease}.fk-endpoint-link__anchor:hover{background-color:var(--fk-endpoint-link-bg-hover, var(--fk-color-surface-muted, #f7f9fb))}.fk-endpoint-link__anchor:focus-visible{outline:none;box-shadow:var(--fk-endpoint-link-focus-ring, var(--fk-focus-ring, 0 0 0 3px rgba(10, 132, 255, .18)))}.fk-endpoint-link__anchor--active,.fk-endpoint-link__anchor--active:hover{background-color:var(--fk-endpoint-link-bg-active, var(--fk-color-primary-light, #dbeafe));color:var(--fk-endpoint-link-color-active, var(--fk-color-primary, #1e3a8a));font-weight:var(--fk-endpoint-link-font-weight-active, var(--fk-font-weight-semibold, 600))}.fk-endpoint-link__badge{flex-shrink:0}.fk-endpoint-link__label{flex:1;min-width:0;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}\n"] }]
53
+ }], propDecorators: { method: [{ type: i0.Input, args: [{ isSignal: true, alias: "method", required: true }] }], label: [{ type: i0.Input, args: [{ isSignal: true, alias: "label", required: true }] }], routerLink: [{ type: i0.Input, args: [{ isSignal: true, alias: "routerLink", required: true }] }], exact: [{ type: i0.Input, args: [{ isSignal: true, alias: "exact", required: false }] }], className: [{ type: i0.Input, args: [{ isSignal: true, alias: "className", required: false }] }], hostClass: [{
54
+ type: HostBinding,
55
+ args: ['class']
56
+ }] } });
57
+
58
+ /**
59
+ * Generated bundle index. Do not edit.
60
+ */
61
+
62
+ export { EndpointLinkComponent };
63
+ //# sourceMappingURL=frame-kit-ui-ng-docs-endpoint-link.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"frame-kit-ui-ng-docs-endpoint-link.mjs","sources":["../../../../packages/ui-ng/docs/endpoint-link/endpoint-link.component.ts","../../../../packages/ui-ng/docs/endpoint-link/endpoint-link.component.html","../../../../packages/ui-ng/docs/endpoint-link/frame-kit-ui-ng-docs-endpoint-link.ts"],"sourcesContent":["import {\n ChangeDetectionStrategy,\n Component,\n computed,\n HostBinding,\n inject,\n input,\n} from '@angular/core';\nimport { RouterLink, RouterLinkActive } from '@angular/router';\n\nimport { AppShellComponent } from '@frame-kit/ui-ng/layouts/app-shell';\nimport { MethodBadgeComponent } from '@frame-kit/ui-ng/docs/method-badge';\nimport type { MethodBadgeMethod } from '@frame-kit/ui-ng/docs/method-badge';\n\n/**\n * Sidebar/list item for an API endpoint in developer documentation.\n *\n * Renders a leading `fk-method-badge` followed by the endpoint label as a\n * single clickable router link. Used to list operations (e.g. \"GET List\n * permissions\", \"POST Create identity\") in a documentation sidebar or any\n * denser endpoint index.\n *\n * Active state is driven by `routerLinkActive`, matching the behavior of\n * `fk-sidenav-link` so every router-aware nav item in the library resolves\n * active state the same way.\n *\n * When rendered inside an `fk-app-shell`, clicks also call `dismissSidenav`\n * on the ancestor shell — this closes the mobile overlay so the user lands\n * directly on the selected endpoint. On desktop it's a no-op.\n */\n@Component({\n selector: 'fk-endpoint-link',\n standalone: true,\n imports: [RouterLink, RouterLinkActive, MethodBadgeComponent],\n changeDetection: ChangeDetectionStrategy.OnPush,\n templateUrl: './endpoint-link.component.html',\n styleUrl: './endpoint-link.component.scss',\n})\nexport class EndpointLinkComponent {\n private readonly shell = inject(AppShellComponent, { optional: true });\n\n // ===== INPUTS =====\n readonly method = input.required<MethodBadgeMethod>();\n readonly label = input.required<string>();\n\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n readonly routerLink = input.required<string | any[]>();\n\n /**\n * Whether to require an exact URL match for the active state. Defaults to\n * false — each endpoint has a unique final path segment so prefix matching\n * resolves to the same thing in practice.\n */\n readonly exact = input<boolean>(false);\n\n // ===== BASE PROPS =====\n readonly className = input<string>('');\n\n // ===== COMPUTED =====\n readonly classes = computed(() =>\n ['fk-endpoint-link', this.className()].filter(Boolean).join(' '),\n );\n\n readonly activeOptions = computed(() => ({ exact: this.exact() }));\n\n @HostBinding('class')\n get hostClass(): string {\n return this.classes();\n }\n\n protected dismiss(): void {\n this.shell?.dismissSidenav();\n }\n}\n","<a\n class=\"fk-endpoint-link__anchor\"\n [routerLink]=\"routerLink()\"\n routerLinkActive=\"fk-endpoint-link__anchor--active\"\n [routerLinkActiveOptions]=\"activeOptions()\"\n (click)=\"$event.stopPropagation(); dismiss()\"\n>\n <fk-method-badge [method]=\"method()\" class=\"fk-endpoint-link__badge\" />\n <span class=\"fk-endpoint-link__label\">{{ label() }}</span>\n</a>\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './index';\n"],"names":[],"mappings":";;;;;;AAcA;;;;;;;;;;;;;;;AAeG;MASU,qBAAqB,CAAA;IACf,KAAK,GAAG,MAAM,CAAC,iBAAiB,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC;;AAG7D,IAAA,MAAM,GAAG,KAAK,CAAC,QAAQ,4EAAqB;AAC5C,IAAA,KAAK,GAAG,KAAK,CAAC,QAAQ,2EAAU;;AAGhC,IAAA,UAAU,GAAG,KAAK,CAAC,QAAQ,gFAAkB;AAEtD;;;;AAIG;AACM,IAAA,KAAK,GAAG,KAAK,CAAU,KAAK,4EAAC;;AAG7B,IAAA,SAAS,GAAG,KAAK,CAAS,EAAE,gFAAC;;IAG7B,OAAO,GAAG,QAAQ,CAAC,MAC1B,CAAC,kBAAkB,EAAE,IAAI,CAAC,SAAS,EAAE,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,EAAA,IAAA,SAAA,GAAA,CAAA,EAAA,SAAA,EAAA,SAAA,EAAA,CAAA,8BAAA,EAAA,CAAA,CACjE;AAEQ,IAAA,aAAa,GAAG,QAAQ,CAAC,OAAO,EAAE,KAAK,EAAE,IAAI,CAAC,KAAK,EAAE,EAAE,CAAC,oFAAC;AAElE,IAAA,IACI,SAAS,GAAA;AACX,QAAA,OAAO,IAAI,CAAC,OAAO,EAAE;IACvB;IAEU,OAAO,GAAA;AACf,QAAA,IAAI,CAAC,KAAK,EAAE,cAAc,EAAE;IAC9B;uGAlCW,qBAAqB,EAAA,IAAA,EAAA,EAAA,EAAA,MAAA,EAAA,EAAA,CAAA,eAAA,CAAA,SAAA,EAAA,CAAA;AAArB,IAAA,OAAA,IAAA,GAAA,EAAA,CAAA,oBAAA,CAAA,EAAA,UAAA,EAAA,QAAA,EAAA,OAAA,EAAA,QAAA,EAAA,IAAA,EAAA,qBAAqB,gwBCtClC,kYAUA,EAAA,MAAA,EAAA,CAAA,myCAAA,CAAA,EAAA,YAAA,EAAA,CAAA,EAAA,IAAA,EAAA,WAAA,EAAA,IAAA,EDuBY,UAAU,EAAA,QAAA,EAAA,cAAA,EAAA,MAAA,EAAA,CAAA,QAAA,EAAA,aAAA,EAAA,UAAA,EAAA,qBAAA,EAAA,OAAA,EAAA,MAAA,EAAA,YAAA,EAAA,kBAAA,EAAA,oBAAA,EAAA,YAAA,EAAA,YAAA,CAAA,EAAA,EAAA,EAAA,IAAA,EAAA,WAAA,EAAA,IAAA,EAAE,gBAAgB,8MAAE,oBAAoB,EAAA,QAAA,EAAA,iBAAA,EAAA,MAAA,EAAA,CAAA,QAAA,EAAA,WAAA,EAAA,IAAA,EAAA,WAAA,CAAA,EAAA,CAAA,EAAA,eAAA,EAAA,EAAA,CAAA,uBAAA,CAAA,MAAA,EAAA,CAAA;;2FAKjD,qBAAqB,EAAA,UAAA,EAAA,CAAA;kBARjC,SAAS;AACE,YAAA,IAAA,EAAA,CAAA,EAAA,QAAA,EAAA,kBAAkB,EAAA,UAAA,EAChB,IAAI,EAAA,OAAA,EACP,CAAC,UAAU,EAAE,gBAAgB,EAAE,oBAAoB,CAAC,EAAA,eAAA,EAC5C,uBAAuB,CAAC,MAAM,EAAA,QAAA,EAAA,kYAAA,EAAA,MAAA,EAAA,CAAA,myCAAA,CAAA,EAAA;;sBA+B9C,WAAW;uBAAC,OAAO;;;AEjEtB;;AAEG;;;;"}
@@ -0,0 +1,43 @@
1
+ import * as i0 from '@angular/core';
2
+ import { input, computed, HostBinding, ChangeDetectionStrategy, Component } from '@angular/core';
3
+
4
+ /**
5
+ * Small rectangular badge showing an HTTP method label (e.g. `GET`, `POST`).
6
+ *
7
+ * Each method has its own hue so consumers can identify the verb in a dense
8
+ * list. Background colors are exposed as CSS variables
9
+ * (`--fk-method-badge-bg-get`, etc.) with defaults baked in so the component
10
+ * renders correctly without a theme.
11
+ */
12
+ class MethodBadgeComponent {
13
+ // ===== INPUTS =====
14
+ method = input.required(...(ngDevMode ? [{ debugName: "method" }] : /* istanbul ignore next */ []));
15
+ // ===== BASE PROPS =====
16
+ className = input('', ...(ngDevMode ? [{ debugName: "className" }] : /* istanbul ignore next */ []));
17
+ id = input(null, ...(ngDevMode ? [{ debugName: "id" }] : /* istanbul ignore next */ []));
18
+ ariaLabel = input(null, ...(ngDevMode ? [{ debugName: "ariaLabel" }] : /* istanbul ignore next */ []));
19
+ // ===== COMPUTED =====
20
+ classes = computed(() => ['fk-method-badge', `fk-method-badge--${this.method()}`, this.className()]
21
+ .filter(Boolean)
22
+ .join(' '), ...(ngDevMode ? [{ debugName: "classes" }] : /* istanbul ignore next */ []));
23
+ label = computed(() => this.method().toUpperCase(), ...(ngDevMode ? [{ debugName: "label" }] : /* istanbul ignore next */ []));
24
+ get hostClass() {
25
+ return this.classes();
26
+ }
27
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: MethodBadgeComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
28
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "21.2.9", type: MethodBadgeComponent, isStandalone: true, selector: "fk-method-badge", inputs: { method: { classPropertyName: "method", publicName: "method", isSignal: true, isRequired: true, transformFunction: null }, className: { classPropertyName: "className", publicName: "className", isSignal: true, isRequired: false, transformFunction: null }, id: { classPropertyName: "id", publicName: "id", isSignal: true, isRequired: false, transformFunction: null }, ariaLabel: { classPropertyName: "ariaLabel", publicName: "ariaLabel", isSignal: true, isRequired: false, transformFunction: null } }, host: { properties: { "class": "this.hostClass" } }, ngImport: i0, template: "<span\n class=\"fk-method-badge__label\"\n [id]=\"id() ?? undefined\"\n [attr.aria-label]=\"ariaLabel()\"\n >{{ label() }}</span\n>\n", styles: [":host{display:inline-flex;align-items:center;justify-content:center;min-width:var(--fk-method-badge-min-width, 3rem);padding:var(--fk-method-badge-padding-block, 2px) var(--fk-method-badge-padding-inline, var(--fk-rhythm-2, .5rem));border-radius:var(--fk-method-badge-radius, var(--fk-radius-sm, .25rem));background-color:var(--fk-method-badge-bg, var(--fk-method-badge-bg-neutral, #d6d6d6));color:var(--fk-method-badge-color, var(--fk-color-text, #1f2d3d));font-family:var(--fk-method-badge-font-family, var(--fk-font-family-mono, ui-monospace, SFMono-Regular, Menlo, monospace));font-size:var(--fk-method-badge-font-size, .6875rem);font-weight:var(--fk-method-badge-font-weight, var(--fk-font-weight-bold, 700));letter-spacing:.05em;line-height:1.4;text-transform:uppercase}:host.fk-method-badge--get{background-color:var(--fk-method-badge-bg-get, #89ecac);color:var(--fk-method-badge-color-get, var(--fk-color-text, #1f2d3d))}:host.fk-method-badge--post{background-color:var(--fk-method-badge-bg-post, #94c4fd);color:var(--fk-method-badge-color-post, var(--fk-color-text, #1f2d3d))}:host.fk-method-badge--put{background-color:var(--fk-method-badge-bg-put, #fbb972);color:var(--fk-method-badge-color-put, var(--fk-color-text, #1f2d3d))}:host.fk-method-badge--patch{background-color:var(--fk-method-badge-bg-patch, #c8a7fb);color:var(--fk-method-badge-color-patch, var(--fk-color-text, #1f2d3d))}:host.fk-method-badge--delete{background-color:var(--fk-method-badge-bg-delete, #fb8d8d);color:var(--fk-method-badge-color-delete, var(--fk-color-text, #1f2d3d))}:host.fk-method-badge--head{background-color:var(--fk-method-badge-bg-head, var(--fk-method-badge-bg-neutral, #d6d6d6));color:var(--fk-method-badge-color-head, var(--fk-color-text, #1f2d3d))}:host.fk-method-badge--options{background-color:var(--fk-method-badge-bg-options, var(--fk-method-badge-bg-neutral, #d6d6d6));color:var(--fk-method-badge-color-options, var(--fk-color-text, #1f2d3d))}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush });
29
+ }
30
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: MethodBadgeComponent, decorators: [{
31
+ type: Component,
32
+ args: [{ selector: 'fk-method-badge', standalone: true, imports: [], changeDetection: ChangeDetectionStrategy.OnPush, template: "<span\n class=\"fk-method-badge__label\"\n [id]=\"id() ?? undefined\"\n [attr.aria-label]=\"ariaLabel()\"\n >{{ label() }}</span\n>\n", styles: [":host{display:inline-flex;align-items:center;justify-content:center;min-width:var(--fk-method-badge-min-width, 3rem);padding:var(--fk-method-badge-padding-block, 2px) var(--fk-method-badge-padding-inline, var(--fk-rhythm-2, .5rem));border-radius:var(--fk-method-badge-radius, var(--fk-radius-sm, .25rem));background-color:var(--fk-method-badge-bg, var(--fk-method-badge-bg-neutral, #d6d6d6));color:var(--fk-method-badge-color, var(--fk-color-text, #1f2d3d));font-family:var(--fk-method-badge-font-family, var(--fk-font-family-mono, ui-monospace, SFMono-Regular, Menlo, monospace));font-size:var(--fk-method-badge-font-size, .6875rem);font-weight:var(--fk-method-badge-font-weight, var(--fk-font-weight-bold, 700));letter-spacing:.05em;line-height:1.4;text-transform:uppercase}:host.fk-method-badge--get{background-color:var(--fk-method-badge-bg-get, #89ecac);color:var(--fk-method-badge-color-get, var(--fk-color-text, #1f2d3d))}:host.fk-method-badge--post{background-color:var(--fk-method-badge-bg-post, #94c4fd);color:var(--fk-method-badge-color-post, var(--fk-color-text, #1f2d3d))}:host.fk-method-badge--put{background-color:var(--fk-method-badge-bg-put, #fbb972);color:var(--fk-method-badge-color-put, var(--fk-color-text, #1f2d3d))}:host.fk-method-badge--patch{background-color:var(--fk-method-badge-bg-patch, #c8a7fb);color:var(--fk-method-badge-color-patch, var(--fk-color-text, #1f2d3d))}:host.fk-method-badge--delete{background-color:var(--fk-method-badge-bg-delete, #fb8d8d);color:var(--fk-method-badge-color-delete, var(--fk-color-text, #1f2d3d))}:host.fk-method-badge--head{background-color:var(--fk-method-badge-bg-head, var(--fk-method-badge-bg-neutral, #d6d6d6));color:var(--fk-method-badge-color-head, var(--fk-color-text, #1f2d3d))}:host.fk-method-badge--options{background-color:var(--fk-method-badge-bg-options, var(--fk-method-badge-bg-neutral, #d6d6d6));color:var(--fk-method-badge-color-options, var(--fk-color-text, #1f2d3d))}\n"] }]
33
+ }], propDecorators: { method: [{ type: i0.Input, args: [{ isSignal: true, alias: "method", required: true }] }], className: [{ type: i0.Input, args: [{ isSignal: true, alias: "className", required: false }] }], id: [{ type: i0.Input, args: [{ isSignal: true, alias: "id", required: false }] }], ariaLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "ariaLabel", required: false }] }], hostClass: [{
34
+ type: HostBinding,
35
+ args: ['class']
36
+ }] } });
37
+
38
+ /**
39
+ * Generated bundle index. Do not edit.
40
+ */
41
+
42
+ export { MethodBadgeComponent };
43
+ //# sourceMappingURL=frame-kit-ui-ng-docs-method-badge.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"frame-kit-ui-ng-docs-method-badge.mjs","sources":["../../../../packages/ui-ng/docs/method-badge/method-badge.component.ts","../../../../packages/ui-ng/docs/method-badge/method-badge.component.html","../../../../packages/ui-ng/docs/method-badge/frame-kit-ui-ng-docs-method-badge.ts"],"sourcesContent":["import {\n ChangeDetectionStrategy,\n Component,\n computed,\n HostBinding,\n input,\n} from '@angular/core';\n\nimport type { MethodBadgeMethod } from './method-badge.types';\n\n/**\n * Small rectangular badge showing an HTTP method label (e.g. `GET`, `POST`).\n *\n * Each method has its own hue so consumers can identify the verb in a dense\n * list. Background colors are exposed as CSS variables\n * (`--fk-method-badge-bg-get`, etc.) with defaults baked in so the component\n * renders correctly without a theme.\n */\n@Component({\n selector: 'fk-method-badge',\n standalone: true,\n imports: [],\n changeDetection: ChangeDetectionStrategy.OnPush,\n templateUrl: './method-badge.component.html',\n styleUrl: './method-badge.component.scss',\n})\nexport class MethodBadgeComponent {\n // ===== INPUTS =====\n readonly method = input.required<MethodBadgeMethod>();\n\n // ===== BASE PROPS =====\n readonly className = input<string>('');\n readonly id = input<string | null>(null);\n readonly ariaLabel = input<string | null>(null);\n\n // ===== COMPUTED =====\n readonly classes = computed(() =>\n ['fk-method-badge', `fk-method-badge--${this.method()}`, this.className()]\n .filter(Boolean)\n .join(' '),\n );\n\n readonly label = computed(() => this.method().toUpperCase());\n\n @HostBinding('class')\n get hostClass(): string {\n return this.classes();\n }\n}\n","<span\n class=\"fk-method-badge__label\"\n [id]=\"id() ?? undefined\"\n [attr.aria-label]=\"ariaLabel()\"\n >{{ label() }}</span\n>\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './index';\n"],"names":[],"mappings":";;;AAUA;;;;;;;AAOG;MASU,oBAAoB,CAAA;;AAEtB,IAAA,MAAM,GAAG,KAAK,CAAC,QAAQ,4EAAqB;;AAG5C,IAAA,SAAS,GAAG,KAAK,CAAS,EAAE,gFAAC;AAC7B,IAAA,EAAE,GAAG,KAAK,CAAgB,IAAI,yEAAC;AAC/B,IAAA,SAAS,GAAG,KAAK,CAAgB,IAAI,gFAAC;;IAGtC,OAAO,GAAG,QAAQ,CAAC,MAC1B,CAAC,iBAAiB,EAAE,CAAA,iBAAA,EAAoB,IAAI,CAAC,MAAM,EAAE,CAAA,CAAE,EAAE,IAAI,CAAC,SAAS,EAAE;SACtE,MAAM,CAAC,OAAO;AACd,SAAA,IAAI,CAAC,GAAG,CAAC,EAAA,IAAA,SAAA,GAAA,CAAA,EAAA,SAAA,EAAA,SAAA,EAAA,CAAA,8BAAA,EAAA,CAAA,CACb;AAEQ,IAAA,KAAK,GAAG,QAAQ,CAAC,MAAM,IAAI,CAAC,MAAM,EAAE,CAAC,WAAW,EAAE,4EAAC;AAE5D,IAAA,IACI,SAAS,GAAA;AACX,QAAA,OAAO,IAAI,CAAC,OAAO,EAAE;IACvB;uGArBW,oBAAoB,EAAA,IAAA,EAAA,EAAA,EAAA,MAAA,EAAA,EAAA,CAAA,eAAA,CAAA,SAAA,EAAA,CAAA;AAApB,IAAA,OAAA,IAAA,GAAA,EAAA,CAAA,oBAAA,CAAA,EAAA,UAAA,EAAA,QAAA,EAAA,OAAA,EAAA,QAAA,EAAA,IAAA,EAAA,oBAAoB,6nBC1BjC,2IAMA,EAAA,MAAA,EAAA,CAAA,k6DAAA,CAAA,EAAA,eAAA,EAAA,EAAA,CAAA,uBAAA,CAAA,MAAA,EAAA,CAAA;;2FDoBa,oBAAoB,EAAA,UAAA,EAAA,CAAA;kBARhC,SAAS;AACE,YAAA,IAAA,EAAA,CAAA,EAAA,QAAA,EAAA,iBAAiB,cACf,IAAI,EAAA,OAAA,EACP,EAAE,EAAA,eAAA,EACM,uBAAuB,CAAC,MAAM,EAAA,QAAA,EAAA,2IAAA,EAAA,MAAA,EAAA,CAAA,k6DAAA,CAAA,EAAA;;sBAsB9C,WAAW;uBAAC,OAAO;;;AE5CtB;;AAEG;;;;"}