@salesforcedevs/arch-components 1.20.17-alpha1

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 (363) hide show
  1. package/lwc.config.json +7 -0
  2. package/package.json +19 -0
  3. package/src/modules/common/context/context.html +1 -0
  4. package/src/modules/common/context/context.ts +137 -0
  5. package/src/modules/common/effectAdapter/__tests__/effectAdapter.test.ts +12 -0
  6. package/src/modules/common/effectAdapter/effectAdapter.html +1 -0
  7. package/src/modules/common/effectAdapter/effectAdapter.ts +18 -0
  8. package/src/modules/common/reflectedElement/__tests__/modules/test/select/select.html +3 -0
  9. package/src/modules/common/reflectedElement/__tests__/modules/test/select/select.ts +7 -0
  10. package/src/modules/common/reflectedElement/__tests__/modules/test/selectTransform/selectTransform.html +3 -0
  11. package/src/modules/common/reflectedElement/__tests__/modules/test/selectTransform/selectTransform.ts +18 -0
  12. package/src/modules/common/reflectedElement/__tests__/reflectedElement.test.ts +75 -0
  13. package/src/modules/common/reflectedElement/reflectedElement.ts +50 -0
  14. package/src/modules/common/slot/__tests__/slot.test.ts +96 -0
  15. package/src/modules/common/slot/slot.ts +20 -0
  16. package/src/modules/sa/coverage/coverage.css +35 -0
  17. package/src/modules/sa/coverage/coverage.html +15 -0
  18. package/src/modules/sa/coverage/coverage.ts +406 -0
  19. package/src/modules/sa/coverage/types.d.ts +26 -0
  20. package/src/modules/sa/expandableSection/expandableSection.css +24 -0
  21. package/src/modules/sa/expandableSection/expandableSection.html +20 -0
  22. package/src/modules/sa/expandableSection/expandableSection.stories.ts +37 -0
  23. package/src/modules/sa/expandableSection/expandableSection.ts +24 -0
  24. package/src/modules/sa/explorer/explorer.css +303 -0
  25. package/src/modules/sa/explorer/explorer.html +403 -0
  26. package/src/modules/sa/explorer/explorer.ts +664 -0
  27. package/src/modules/sa/explorer/types.d.ts +60 -0
  28. package/src/modules/sa/gallery/gallery.css +358 -0
  29. package/src/modules/sa/gallery/gallery.html +65 -0
  30. package/src/modules/sa/gallery/gallery.ts +300 -0
  31. package/src/modules/sa/gallery/types.d.ts +35 -0
  32. package/src/modules/sa/socialShare/socialShare.css +49 -0
  33. package/src/modules/sa/socialShare/socialShare.html +56 -0
  34. package/src/modules/sa/socialShare/socialShare.ts +29 -0
  35. package/src/modules/shared/a11y/a11y.ts +25 -0
  36. package/src/modules/shared/children/children.ts +29 -0
  37. package/src/modules/shared/color/color.ts +52 -0
  38. package/src/modules/shared/debounce/debounce.ts +32 -0
  39. package/src/modules/shared/dialog/dialog.ts +154 -0
  40. package/src/modules/shared/elements/__tests__/overflow.test.ts +39 -0
  41. package/src/modules/shared/elements/overflow.ts +71 -0
  42. package/src/modules/shared/fetch/fetch.ts +52 -0
  43. package/src/modules/shared/helpers/helpers.ts +141 -0
  44. package/src/modules/shared/i18n/i18n.ts +74 -0
  45. package/src/modules/shared/labels/__tests__/helpers.test.ts +107 -0
  46. package/src/modules/shared/labels/__tests__/pointHelpers.test.ts +33 -0
  47. package/src/modules/shared/labels/__tests__/timeHelpers.test.ts +89 -0
  48. package/src/modules/shared/labels/helpers.ts +23 -0
  49. package/src/modules/shared/labels/pointHelpers.ts +47 -0
  50. package/src/modules/shared/labels/timeHelpers.ts +182 -0
  51. package/src/modules/shared/labels/types.d.ts +5 -0
  52. package/src/modules/shared/logger/logger.ts +33 -0
  53. package/src/modules/shared/menu/menu.ts +239 -0
  54. package/src/modules/shared/overflow/__tests__/overflow.test.ts +39 -0
  55. package/src/modules/shared/overflow/overflow.ts +71 -0
  56. package/src/modules/shared/polling-request.ts +97 -0
  57. package/src/modules/shared/testutils.ts +118 -0
  58. package/src/modules/shared/track/track.ts +23 -0
  59. package/src/modules/shared/trailhead.ts +123 -0
  60. package/src/modules/shared/types.d.ts +1 -0
  61. package/src/modules/shared/useEffectAttr.ts +16 -0
  62. package/src/modules/shared/withState.ts +21 -0
  63. package/src/modules/tds/appLauncher/__fixtures__/index.ts +34 -0
  64. package/src/modules/tds/appLauncher/__tests__/appLauncher.test.ts +119 -0
  65. package/src/modules/tds/appLauncher/appLauncher.css +65 -0
  66. package/src/modules/tds/appLauncher/appLauncher.html +38 -0
  67. package/src/modules/tds/appLauncher/appLauncher.stories.ts +39 -0
  68. package/src/modules/tds/appLauncher/appLauncher.ts +79 -0
  69. package/src/modules/tds/appLauncher/types.ts +8 -0
  70. package/src/modules/tds/avatar/__tests__/avatar.test.ts +11 -0
  71. package/src/modules/tds/avatar/avatar.css +77 -0
  72. package/src/modules/tds/avatar/avatar.html +36 -0
  73. package/src/modules/tds/avatar/avatar.stories.ts +64 -0
  74. package/src/modules/tds/avatar/avatar.ts +50 -0
  75. package/src/modules/tds/badge/__tests__/badge.test.js +11 -0
  76. package/src/modules/tds/badge/badge.css +22 -0
  77. package/src/modules/tds/badge/badge.html +5 -0
  78. package/src/modules/tds/badge/badge.stories.ts +10 -0
  79. package/src/modules/tds/badge/badge.ts +9 -0
  80. package/src/modules/tds/button/__tests__/button.test.ts +52 -0
  81. package/src/modules/tds/button/button.css +1 -0
  82. package/src/modules/tds/button/button.html +20 -0
  83. package/src/modules/tds/button/button.stories.js +54 -0
  84. package/src/modules/tds/button/button.ts +59 -0
  85. package/src/modules/tds/buttonIcon/__tests__/buttonIcon.test.ts +17 -0
  86. package/src/modules/tds/buttonIcon/buttonIcon.css +1 -0
  87. package/src/modules/tds/buttonIcon/buttonIcon.html +12 -0
  88. package/src/modules/tds/buttonIcon/buttonIcon.stories.js +38 -0
  89. package/src/modules/tds/buttonIcon/buttonIcon.ts +6 -0
  90. package/src/modules/tds/buttonIconLink/buttonIconLink.css +1 -0
  91. package/src/modules/tds/buttonIconLink/buttonIconLink.html +14 -0
  92. package/src/modules/tds/buttonIconLink/buttonIconLink.stories.ts +32 -0
  93. package/src/modules/tds/buttonIconLink/buttonIconLink.ts +9 -0
  94. package/src/modules/tds/buttonLink/__tests__/buttonLink.test.ts +17 -0
  95. package/src/modules/tds/buttonLink/buttonLink.css +1 -0
  96. package/src/modules/tds/buttonLink/buttonLink.html +19 -0
  97. package/src/modules/tds/buttonLink/buttonLink.stories.js +24 -0
  98. package/src/modules/tds/buttonLink/buttonLink.ts +8 -0
  99. package/src/modules/tds/buttonStyles/buttonStyles.css +232 -0
  100. package/src/modules/tds/childSummary/__tests__/childSummary.test.js +99 -0
  101. package/src/modules/tds/childSummary/childSummary.css +74 -0
  102. package/src/modules/tds/childSummary/childSummary.html +38 -0
  103. package/src/modules/tds/childSummary/childSummary.stories.ts +40 -0
  104. package/src/modules/tds/childSummary/childSummary.ts +63 -0
  105. package/src/modules/tds/childSummary/types.d.ts +10 -0
  106. package/src/modules/tds/contentChildListItem/__tests__/contentChildListItem.test.ts +32 -0
  107. package/src/modules/tds/contentChildListItem/contentChildListItem.css +1 -0
  108. package/src/modules/tds/contentChildListItem/contentChildListItem.html +10 -0
  109. package/src/modules/tds/contentChildListItem/contentChildListItem.stories.ts +46 -0
  110. package/src/modules/tds/contentChildListItem/contentChildListItem.ts +34 -0
  111. package/src/modules/tds/contentIcon/contentIcon.css +47 -0
  112. package/src/modules/tds/contentIcon/contentIcon.html +15 -0
  113. package/src/modules/tds/contentIcon/contentIcon.stories.js +110 -0
  114. package/src/modules/tds/contentIcon/contentIcon.ts +66 -0
  115. package/src/modules/tds/contextAdapter/__tests__/contextAdapter.test.ts +76 -0
  116. package/src/modules/tds/contextAdapter/constants.ts +1 -0
  117. package/src/modules/tds/contextAdapter/contextAdapter.html +1 -0
  118. package/src/modules/tds/contextAdapter/contextAdapter.ts +54 -0
  119. package/src/modules/tds/dialogStyles/dialogStyles.css +90 -0
  120. package/src/modules/tds/footerLinks/__tests__/__snapshots__/footerLinks.test.ts.snap +3 -0
  121. package/src/modules/tds/footerLinks/__tests__/footerLinks.test.ts +142 -0
  122. package/src/modules/tds/footerLinks/footerLinks.css +80 -0
  123. package/src/modules/tds/footerLinks/footerLinks.html +30 -0
  124. package/src/modules/tds/footerLinks/footerLinks.ts +48 -0
  125. package/src/modules/tds/footerLinks/types.ts +11 -0
  126. package/src/modules/tds/footerMfe/footerMfe.html +3 -0
  127. package/src/modules/tds/footerMfe/footerMfe.ts +19 -0
  128. package/src/modules/tds/headerAvatar/__tests__/headerAvatar.test.ts +43 -0
  129. package/src/modules/tds/headerAvatar/headerAvatar.css +45 -0
  130. package/src/modules/tds/headerAvatar/headerAvatar.html +25 -0
  131. package/src/modules/tds/headerAvatar/headerAvatar.ts +15 -0
  132. package/src/modules/tds/headerHelpButton/__tests__/headerHelpButton.test.ts +32 -0
  133. package/src/modules/tds/headerHelpButton/headerHelpButton.css +14 -0
  134. package/src/modules/tds/headerHelpButton/headerHelpButton.html +19 -0
  135. package/src/modules/tds/headerHelpButton/headerHelpButton.ts +12 -0
  136. package/src/modules/tds/heading/__tests__/heading.test.ts +50 -0
  137. package/src/modules/tds/heading/heading.css +1 -0
  138. package/src/modules/tds/heading/heading.html +9 -0
  139. package/src/modules/tds/heading/heading.stories.ts +36 -0
  140. package/src/modules/tds/heading/heading.ts +36 -0
  141. package/src/modules/tds/icon/icon.css +28 -0
  142. package/src/modules/tds/icon/icon.html +17 -0
  143. package/src/modules/tds/icon/icon.stories.js +18 -0
  144. package/src/modules/tds/icon/icon.ts +79 -0
  145. package/src/modules/tds/input/__tests__/input.test.ts +41 -0
  146. package/src/modules/tds/input/input.css +34 -0
  147. package/src/modules/tds/input/input.html +12 -0
  148. package/src/modules/tds/input/input.stories.ts +25 -0
  149. package/src/modules/tds/input/input.ts +41 -0
  150. package/src/modules/tds/instrumentation/instrumentation.css +0 -0
  151. package/src/modules/tds/instrumentation/instrumentation.html +1 -0
  152. package/src/modules/tds/instrumentation/instrumentation.ts +113 -0
  153. package/src/modules/tds/pbCard/pbCard.css +28 -0
  154. package/src/modules/tds/pbCard/pbCard.html +21 -0
  155. package/src/modules/tds/pbCard/pbCard.ts +18 -0
  156. package/src/modules/tds/pill/__tests__/pill.test.ts +56 -0
  157. package/src/modules/tds/pill/pill.css +70 -0
  158. package/src/modules/tds/pill/pill.html +17 -0
  159. package/src/modules/tds/pill/pill.stories.ts +41 -0
  160. package/src/modules/tds/pill/pill.ts +34 -0
  161. package/src/modules/tds/progressBar/__tests__/progressBar.test.js +11 -0
  162. package/src/modules/tds/progressBar/progressBar.css +42 -0
  163. package/src/modules/tds/progressBar/progressBar.html +14 -0
  164. package/src/modules/tds/progressBar/progressBar.stories.ts +24 -0
  165. package/src/modules/tds/progressBar/progressBar.ts +14 -0
  166. package/src/modules/tds/radio/__tests__/radio.test.ts +29 -0
  167. package/src/modules/tds/radio/radio.css +89 -0
  168. package/src/modules/tds/radio/radio.html +17 -0
  169. package/src/modules/tds/radio/radio.stories.ts +31 -0
  170. package/src/modules/tds/radio/radio.ts +32 -0
  171. package/src/modules/tds/reset/reset.css +39 -0
  172. package/src/modules/tds/search/__fixtures__/index.ts +32 -0
  173. package/src/modules/tds/search/__tests__/search.test.ts +235 -0
  174. package/src/modules/tds/search/lib/__tests__/__snapshots__/listbox.test.ts.snap +115 -0
  175. package/src/modules/tds/search/lib/__tests__/listbox.test.ts +192 -0
  176. package/src/modules/tds/search/lib/listbox.ts +209 -0
  177. package/src/modules/tds/search/search.css +122 -0
  178. package/src/modules/tds/search/search.html +21 -0
  179. package/src/modules/tds/search/search.stories.ts +20 -0
  180. package/src/modules/tds/search/search.ts +107 -0
  181. package/src/modules/tds/search/types.d.ts +22 -0
  182. package/src/modules/tds/searchList/searchList.css +120 -0
  183. package/src/modules/tds/searchList/searchList.html +43 -0
  184. package/src/modules/tds/searchList/searchList.stories.ts +10 -0
  185. package/src/modules/tds/searchList/searchList.ts +53 -0
  186. package/src/modules/tds/select/__tests__/select.test.ts +150 -0
  187. package/src/modules/tds/select/select.css +42 -0
  188. package/src/modules/tds/select/select.html +24 -0
  189. package/src/modules/tds/select/select.stories.ts +59 -0
  190. package/src/modules/tds/select/select.ts +60 -0
  191. package/src/modules/tds/spinner/__tests__/spinner.test.ts +11 -0
  192. package/src/modules/tds/spinner/spinner.css +194 -0
  193. package/src/modules/tds/spinner/spinner.html +9 -0
  194. package/src/modules/tds/spinner/spinner.stories.ts +20 -0
  195. package/src/modules/tds/spinner/spinner.ts +15 -0
  196. package/src/modules/tds/styles/styles.css +24 -0
  197. package/src/modules/tds/summary/__tests__/summary.test.ts +135 -0
  198. package/src/modules/tds/summary/summary.css +135 -0
  199. package/src/modules/tds/summary/summary.html +69 -0
  200. package/src/modules/tds/summary/summary.stories.js +148 -0
  201. package/src/modules/tds/summary/summary.ts +95 -0
  202. package/src/modules/tds/tab/__tests__/tab.test.ts +25 -0
  203. package/src/modules/tds/tab/tab.css +3 -0
  204. package/src/modules/tds/tab/tab.html +5 -0
  205. package/src/modules/tds/tab/tab.ts +46 -0
  206. package/src/modules/tds/tabset/__tests__/tabset.test.ts +108 -0
  207. package/src/modules/tds/tabset/tabset.css +112 -0
  208. package/src/modules/tds/tabset/tabset.html +63 -0
  209. package/src/modules/tds/tabset/tabset.stories.ts +32 -0
  210. package/src/modules/tds/tabset/tabset.ts +232 -0
  211. package/src/modules/tds/themeProvider/themeProvider.css +502 -0
  212. package/src/modules/tds/themeProvider/themeProvider.html +3 -0
  213. package/src/modules/tds/themeProvider/themeProvider.ts +37 -0
  214. package/src/modules/tds/tile/tile.css +23 -0
  215. package/src/modules/tds/tile/tile.html +5 -0
  216. package/src/modules/tds/tile/tile.stories.js +14 -0
  217. package/src/modules/tds/tile/tile.ts +12 -0
  218. package/src/modules/tds/xsfMfeEvents/xsfMfeEvents.html +1 -0
  219. package/src/modules/tds/xsfMfeEvents/xsfMfeEvents.ts +47 -0
  220. package/src/modules/th/contextAdapter/__tests__/contextAdapter.test.ts +104 -0
  221. package/src/modules/th/contextAdapter/contextAdapter.html +1 -0
  222. package/src/modules/th/contextAdapter/contextAdapter.ts +49 -0
  223. package/src/modules/th/favoriteButton/__tests__/favoriteButton.test.ts +56 -0
  224. package/src/modules/th/favoriteButton/favoriteButton.css +3 -0
  225. package/src/modules/th/favoriteButton/favoriteButton.html +15 -0
  226. package/src/modules/th/favoriteButton/favoriteButton.stories.js +30 -0
  227. package/src/modules/th/favoriteButton/favoriteButton.ts +84 -0
  228. package/src/modules/th/favoriteButton/mocks/index.ts +12 -0
  229. package/src/modules/th/search/__fixtures__/index.ts +14 -0
  230. package/src/modules/th/search/__tests__/search.test.ts +233 -0
  231. package/src/modules/th/search/constants.ts +2 -0
  232. package/src/modules/th/search/mocks/index.ts +30 -0
  233. package/src/modules/th/search/mocks/responses.ts +54 -0
  234. package/src/modules/th/search/search.css +4 -0
  235. package/src/modules/th/search/search.html +12 -0
  236. package/src/modules/th/search/search.ts +172 -0
  237. package/src/modules/th/search/types.d.ts +29 -0
  238. package/src/modules/th/tbid/__tests__/__snapshots__/tbid.test.ts.snap +3 -0
  239. package/src/modules/th/tbid/__tests__/tbid.test.ts +242 -0
  240. package/src/modules/th/tbid/tbid.html +1 -0
  241. package/src/modules/th/tbid/tbid.stories.mdx +25 -0
  242. package/src/modules/th/tbid/tbid.ts +215 -0
  243. package/src/modules/tm/card/__tests__/card.test.ts +65 -0
  244. package/src/modules/tm/card/card.css +131 -0
  245. package/src/modules/tm/card/card.html +81 -0
  246. package/src/modules/tm/card/card.ts +269 -0
  247. package/src/modules/tm/cardBase/cardBase.css +11 -0
  248. package/src/modules/tm/cardGridA/cardGridA.css +11 -0
  249. package/src/modules/tm/cardGridA/cardGridA.html +21 -0
  250. package/src/modules/tm/cardGridA/cardGridA.stories.js +107 -0
  251. package/src/modules/tm/cardGridA/cardGridA.ts +24 -0
  252. package/src/modules/tm/cardGridB/cardGridB.css +88 -0
  253. package/src/modules/tm/cardGridB/cardGridB.html +20 -0
  254. package/src/modules/tm/cardGridB/cardGridB.stories.js +58 -0
  255. package/src/modules/tm/cardGridB/cardGridB.ts +19 -0
  256. package/src/modules/tm/cardGridC/cardGridC.css +24 -0
  257. package/src/modules/tm/cardGridC/cardGridC.html +22 -0
  258. package/src/modules/tm/cardGridC/cardGridC.stories.js +42 -0
  259. package/src/modules/tm/cardGridC/cardGridC.ts +11 -0
  260. package/src/modules/tm/cardGridD/cardGridD.css +17 -0
  261. package/src/modules/tm/cardGridD/cardGridD.html +20 -0
  262. package/src/modules/tm/cardGridD/cardGridD.stories.js +34 -0
  263. package/src/modules/tm/cardGridD/cardGridD.ts +7 -0
  264. package/src/modules/tm/cardNew/cardNew.css +31 -0
  265. package/src/modules/tm/cardNew/cardNew.html +29 -0
  266. package/src/modules/tm/cardNew/cardNew.ts +66 -0
  267. package/src/modules/tm/content/__fixtures__/index.ts +884 -0
  268. package/src/modules/tm/content/__tests__/content.test.ts +95 -0
  269. package/src/modules/tm/content/content.css +641 -0
  270. package/src/modules/tm/content/content.html +53 -0
  271. package/src/modules/tm/content/content.stories.js +14 -0
  272. package/src/modules/tm/content/content.ts +171 -0
  273. package/src/modules/tm/endCapA/__tests__/endCapA.test.ts +52 -0
  274. package/src/modules/tm/endCapA/endCapA.css +64 -0
  275. package/src/modules/tm/endCapA/endCapA.html +21 -0
  276. package/src/modules/tm/endCapA/endCapA.stories.js +37 -0
  277. package/src/modules/tm/endCapA/endCapA.ts +23 -0
  278. package/src/modules/tm/eventsA/eventsA.css +107 -0
  279. package/src/modules/tm/eventsA/eventsA.html +26 -0
  280. package/src/modules/tm/eventsA/eventsA.stories.js +51 -0
  281. package/src/modules/tm/eventsA/eventsA.ts +48 -0
  282. package/src/modules/tm/faqA/faqA.css +87 -0
  283. package/src/modules/tm/faqA/faqA.html +27 -0
  284. package/src/modules/tm/faqA/faqA.stories.js +25 -0
  285. package/src/modules/tm/faqA/faqA.ts +40 -0
  286. package/src/modules/tm/featureGridA/__tests__/featureGridA.test.ts +116 -0
  287. package/src/modules/tm/featureGridA/featureGridA.css +95 -0
  288. package/src/modules/tm/featureGridA/featureGridA.html +34 -0
  289. package/src/modules/tm/featureGridA/featureGridA.stories.js +45 -0
  290. package/src/modules/tm/featureGridA/featureGridA.ts +59 -0
  291. package/src/modules/tm/footnote/footnote.css +28 -0
  292. package/src/modules/tm/footnote/footnote.html +3 -0
  293. package/src/modules/tm/footnote/footnote.stories.js +29 -0
  294. package/src/modules/tm/footnote/footnote.ts +35 -0
  295. package/src/modules/tm/heroA/__tests__/heroA.test.ts +51 -0
  296. package/src/modules/tm/heroA/heroA.css +116 -0
  297. package/src/modules/tm/heroA/heroA.html +27 -0
  298. package/src/modules/tm/heroA/heroA.stories.js +49 -0
  299. package/src/modules/tm/heroA/heroA.ts +56 -0
  300. package/src/modules/tm/heroB/heroB.css +78 -0
  301. package/src/modules/tm/heroB/heroB.html +26 -0
  302. package/src/modules/tm/heroB/heroB.stories.js +44 -0
  303. package/src/modules/tm/heroB/heroB.ts +26 -0
  304. package/src/modules/tm/page/__tests__/page.test.ts +35 -0
  305. package/src/modules/tm/page/page.css +3 -0
  306. package/src/modules/tm/page/page.html +3 -0
  307. package/src/modules/tm/page/page.stories.js +10 -0
  308. package/src/modules/tm/page/page.ts +3 -0
  309. package/src/modules/tm/pageHeaderA/pageHeaderA.css +82 -0
  310. package/src/modules/tm/pageHeaderA/pageHeaderA.html +24 -0
  311. package/src/modules/tm/pageHeaderA/pageHeaderA.stories.js +18 -0
  312. package/src/modules/tm/pageHeaderA/pageHeaderA.ts +51 -0
  313. package/src/modules/tm/pageNavigationA/pageNavigationA.css +41 -0
  314. package/src/modules/tm/pageNavigationA/pageNavigationA.html +9 -0
  315. package/src/modules/tm/pageNavigationA/pageNavigationA.stories.js +34 -0
  316. package/src/modules/tm/pageNavigationA/pageNavigationA.ts +18 -0
  317. package/src/modules/tm/promoA/__tests__/promoA.test.ts +89 -0
  318. package/src/modules/tm/promoA/promoA.css +95 -0
  319. package/src/modules/tm/promoA/promoA.html +22 -0
  320. package/src/modules/tm/promoA/promoA.stories.js +38 -0
  321. package/src/modules/tm/promoA/promoA.ts +62 -0
  322. package/src/modules/tm/sectionA/sectionA.css +64 -0
  323. package/src/modules/tm/sectionA/sectionA.html +21 -0
  324. package/src/modules/tm/sectionA/sectionA.stories.js +18 -0
  325. package/src/modules/tm/sectionA/sectionA.ts +27 -0
  326. package/src/modules/tm/sectionSpacer/sectionSpacer.css +4 -0
  327. package/src/modules/tm/sectionSpacer/sectionSpacer.html +1 -0
  328. package/src/modules/tm/sectionSpacer/sectionSpacer.ts +3 -0
  329. package/src/modules/tm/skillsCardA/skillsCardA.css +73 -0
  330. package/src/modules/tm/skillsCardA/skillsCardA.html +37 -0
  331. package/src/modules/tm/skillsCardA/skillsCardA.ts +38 -0
  332. package/src/modules/tm/skillsGridA/skillsGridA.css +12 -0
  333. package/src/modules/tm/skillsGridA/skillsGridA.html +5 -0
  334. package/src/modules/tm/skillsGridA/skillsGridA.stories.ts +65 -0
  335. package/src/modules/tm/skillsGridA/skillsGridA.ts +3 -0
  336. package/src/modules/tm/statsA/statsA.css +26 -0
  337. package/src/modules/tm/statsA/statsA.html +10 -0
  338. package/src/modules/tm/statsA/statsA.stories.js +29 -0
  339. package/src/modules/tm/statsA/statsA.ts +20 -0
  340. package/src/modules/tm/textItem/textItem.css +53 -0
  341. package/src/modules/tm/textItem/textItem.html +18 -0
  342. package/src/modules/tm/textItem/textItem.ts +32 -0
  343. package/src/modules/tm/textItemGridA/textItemGridA.css +11 -0
  344. package/src/modules/tm/textItemGridA/textItemGridA.html +15 -0
  345. package/src/modules/tm/textItemGridA/textItemGridA.stories.js +67 -0
  346. package/src/modules/tm/textItemGridA/textItemGridA.ts +20 -0
  347. package/src/modules/tm/threeCardGrid/threeCardGrid.css +6 -0
  348. package/src/modules/tm/threeCardGrid/threeCardGrid.html +5 -0
  349. package/src/modules/tm/threeCardGrid/threeCardGrid.ts +3 -0
  350. package/src/modules/tm/trailblazersA/trailblazersA.css +70 -0
  351. package/src/modules/tm/trailblazersA/trailblazersA.html +42 -0
  352. package/src/modules/tm/trailblazersA/trailblazersA.stories.js +52 -0
  353. package/src/modules/tm/trailblazersA/trailblazersA.ts +43 -0
  354. package/src/modules/tm/utils/utils.ts +18 -0
  355. package/src/modules/tm/youtube/youtube.css +7 -0
  356. package/src/modules/tm/youtube/youtube.html +10 -0
  357. package/src/modules/tm/youtube/youtube.stories.js +15 -0
  358. package/src/modules/tm/youtube/youtube.ts +27 -0
  359. package/src/modules/ui/focusTrap/focusTrap.html +5 -0
  360. package/src/modules/ui/focusTrap/focusTrap.ts +104 -0
  361. package/src/modules/ui/focusVisible/__tests__/focusVisible.test.ts +95 -0
  362. package/src/modules/ui/focusVisible/focusVisible.html +3 -0
  363. package/src/modules/ui/focusVisible/focusVisible.ts +46 -0
@@ -0,0 +1,664 @@
1
+ import { LightningElement, api, track } from 'lwc';
2
+ //import { ExpandableSection } from '../expandableSection/expandableSection';
3
+ import { Tab } from '../../tds/tabset/tabset';
4
+ import { Pattern, Behavior, Location, VersionInfo, Filter } from './types';
5
+ import jsPDF from 'jspdf';
6
+ import { isDisabled } from '@a11y/focus-trap';
7
+ import { debounce } from 'shared/debounce';
8
+ import { sendInteractionEvent, InteractionEventTypes } from 'shared/helpers';
9
+
10
+ export default class Explorer extends LightningElement {
11
+
12
+ // get the inuts from the calling page
13
+ _content: any;
14
+
15
+ // lets get the inputs from the form
16
+ private _keywordFilter: string = '';
17
+ private _selectedTrusted: string = '-1';
18
+ private _selectedEasy: string = '-1';
19
+ private _selectedAdaptable: string = '-1';
20
+ private _selectedLocation: string = '-1';
21
+ private _selectedProductArea: string = '-1';
22
+
23
+ // set up some controlling sys vars
24
+ private isLoading = true;
25
+ private filterData = '/assets/data/wa_framework.json';
26
+ private feedbackURL = 'https://docs.google.com/forms/d/e/1FAIpQLSf172WosVDuSjMnTS2tGL8024TyBswpWTv4vNjwfbwces0HlQ/viewform';
27
+ @api private version: string = '';
28
+ private frameworkArr: any;
29
+ private trustedArr: Behavior[] = [];
30
+ private easyArr: Behavior[] = [];
31
+ private adaptableArr: Behavior[] = [];
32
+ private locationsArr: Location[] = [];
33
+ private productAreasArr: Location[] = [];
34
+ private selectedFilters: Filter[] = [];
35
+ private currentPageIndex = 0;
36
+ private pageSize = 10;
37
+ private shareUrl = window.location.href;
38
+
39
+
40
+ // vars for pdf export
41
+ private logoURL = '/assets/images/architects_logo_horizontal_bg.png';
42
+ private logoImageData: any;
43
+
44
+
45
+ // lets set the pattern data (this includes anti-patterns)
46
+ entireLibrary: Pattern[] = [];
47
+ allPatterns: Pattern[] = [];
48
+ allAntiPatterns: Pattern[] = [];
49
+ filteredPatterns: Pattern[] = [];
50
+ filteredAntiPatterns: Pattern[] = [];
51
+
52
+ connectedCallback(): void {
53
+
54
+ this.loadImage(this.logoURL).then(data => {
55
+ this.logoImageData = data;
56
+ })
57
+ .catch(error => {
58
+ console.error('Error loading image:', error);
59
+ });
60
+ }
61
+
62
+ @api
63
+ set content(value) {
64
+ if (this._content !== value) {
65
+ this._content = value;
66
+ this.fetchFilterData();
67
+ this.fetchPatternData();
68
+ }
69
+
70
+ }
71
+ get content() {
72
+ return this._content;
73
+ }
74
+
75
+ // get the patterns loaded into a variable
76
+ async fetchPatternData() {
77
+ try {
78
+ const response = await fetch(this._content);
79
+ const data = await response.json();
80
+ this.allPatterns = this.sortPatterns(data.values[0][0].Patterns as Pattern[]);
81
+ this.allAntiPatterns = this.sortPatterns(data.values[0][0].AntiPatterns as Pattern[]);
82
+ this.removeEmptyFilterOptions();
83
+ this.checkURLParams();
84
+ this.applyFilters();
85
+
86
+ } catch (error: any) {
87
+ console.error("An error occurred fetching the library:", error?.message || String(error));
88
+ }
89
+ }
90
+ private removeEmptyFilterOptions = () => {
91
+ const availableProductAreas = [...new Set(
92
+ [...this.allPatterns.map(item => item.ProductArea),
93
+ ...this.allAntiPatterns.map(item => item.ProductArea)
94
+ ]
95
+ )].sort();
96
+
97
+ this.productAreasArr = availableProductAreas.map(area => ({ Name: area, isDisabled: false }))
98
+ }
99
+ private sortPatterns(arr: any[]) {
100
+ return arr.sort((a, b) => {
101
+ // Compare by CapabilityWeight
102
+ if (a.CapabilityWeight > b.CapabilityWeight) return -1;
103
+ if (a.CapabilityWeight < b.CapabilityWeight) return 1;
104
+
105
+ // If CapabilityWeight is equal, compare by BehaviorWeight
106
+ if (a.BehaviorWeight > b.BehaviorWeight) return -1;
107
+ if (a.BehaviorWeight < b.BehaviorWeight) return 1;
108
+
109
+ // If BehaviorWeight is equal, compare by DimensionWeight
110
+ if (a.DimensionWeight > b.DimensionWeight) return -1;
111
+ if (a.DimensionWeight < b.DimensionWeight) return 1;
112
+
113
+ // If DimensionWeight is equal, compare by ConsiderationWeight
114
+ if (a.ConsiderationWeight > b.ConsiderationWeight) return -1;
115
+ if (a.ConsiderationWeight < b.ConsiderationWeight) return 1;
116
+
117
+ // If all properties are equal, consider the elements equal in this sort context
118
+ return 0;
119
+ });
120
+ }
121
+
122
+ private get hasPatterns(): boolean {
123
+ return this.filteredPatterns.length > 0;
124
+ }
125
+
126
+ private get hasAntiPatterns(): boolean {
127
+ return this.filteredAntiPatterns.length > 0;
128
+ }
129
+
130
+ handleFeedbackClick() {
131
+ window.open(this.feedbackURL, '_blank');
132
+ }
133
+
134
+ //#region FILTER FUNCTIONS
135
+
136
+ async fetchFilterData() {
137
+ try {
138
+
139
+ fetch(this.filterData).then((response) => response.json()).then((data) => {
140
+ // get the entire framework
141
+ this.frameworkArr = data.values[0][0].Capabilities;
142
+
143
+ // populate the framework dropdowns
144
+ this.trustedArr = this.frameworkArr.filter((capability: any) => capability.Name === "Trusted")[0].Behaviors.sort((a: any, b: any) => b.Weight - a.Weight);
145
+ this.trustedArr.forEach((behavior) => behavior.Dimensions.map((dim: any) => dim.isDisabled = false));
146
+
147
+ this.easyArr = this.frameworkArr.filter((capability: any) => capability.Name === "Easy")[0].Behaviors.sort((a: any, b: any) => b.Weight - a.Weight);
148
+ this.easyArr.forEach((behavior) => behavior.Dimensions.map((dim: any) => dim.isDisabled = false));
149
+
150
+ this.adaptableArr = this.frameworkArr.filter((capability: any) => capability.Name === "Adaptable")[0].Behaviors.sort((a: any, b: any) => b.Weight - a.Weight);
151
+ this.adaptableArr.forEach((behavior) => behavior.Dimensions.map(dim => dim.isDisabled = false));
152
+
153
+ this.locationsArr.push(...data.values[0][0].Locations);
154
+ this.locationsArr.forEach(loc => loc.isDisabled = false);
155
+
156
+ this.productAreasArr.push(...data.values[0][0].ProductAreas);
157
+ this.productAreasArr.forEach(area => area.isDisabled = false);
158
+
159
+ });
160
+
161
+ } catch (error: any) {
162
+ console.error("An error occurred getting the filter list:", error?.message || String(error));
163
+ }
164
+ }
165
+
166
+ filterChange(evt: any) {
167
+ if (evt.detail == "-1")
168
+ return;
169
+ else {
170
+ let newFilter: Filter = {
171
+ Type: evt.target.id,
172
+ Name: evt.detail
173
+ };
174
+ // Check if the filter already exists in the array
175
+ let filterExists = this.selectedFilters.some(filter => filter.Type === newFilter.Type && filter.Name === newFilter.Name);
176
+ if (!filterExists) {
177
+ this.selectedFilters.push(newFilter);
178
+ this.setDimensionOption(newFilter.Type, newFilter.Name, true);
179
+ }
180
+
181
+ this.applyFilters();
182
+ }
183
+ }
184
+
185
+ removeFilter(evt: any) {
186
+ let index = this.selectedFilters.findIndex(filter => filter.Name === evt.target.innerText);
187
+ this.setDimensionOption(this.selectedFilters[index].Type, this.selectedFilters[index].Name, false);
188
+ this.selectedFilters.splice(index, 1);
189
+ this.applyFilters();
190
+ }
191
+
192
+ private sendInteractionEvent = debounce((event,target)=>{
193
+ sendInteractionEvent("Explorer Search",InteractionEventTypes.INPUT_CHANGE,event,target);
194
+ },1000);
195
+ // handle typing in the search box
196
+ keywordFilterChange(evt: InputEvent) {
197
+ const target = (evt.currentTarget as HTMLInputElement);
198
+ this.sendInteractionEvent(evt,target);
199
+ this._keywordFilter = target.value;
200
+ this.applyFilters();
201
+ }
202
+
203
+
204
+ async applyFilters() {
205
+ try {
206
+ this.filteredPatterns = [...this.allPatterns];
207
+ this.filteredAntiPatterns = [...this.allAntiPatterns];
208
+ let frameworkFilters = this.selectedFilters.filter(filter => filter.Type !== 'Location' && filter.Type !== 'ProductArea');
209
+ let locationFilters = this.selectedFilters.filter(filter => filter.Type === 'Location');
210
+ let productAreaFilters = this.selectedFilters.filter(filter => filter.Type === 'ProductArea');
211
+
212
+ if (frameworkFilters.length > 0) {
213
+ this.filteredPatterns = this.filteredPatterns.filter(pattern =>
214
+ frameworkFilters.some(filter => (pattern.Capability === filter.Type && pattern.Dimension === filter.Name))
215
+ );
216
+
217
+ this.filteredAntiPatterns = this.filteredAntiPatterns.filter(pattern =>
218
+ frameworkFilters.some(filter => (pattern.Capability === filter.Type && pattern.Dimension === filter.Name))
219
+ );
220
+ }
221
+ if (locationFilters.length > 0) {
222
+ this.filteredPatterns = this.filteredPatterns.filter(pattern =>
223
+ locationFilters.some(filter => (filter.Type === 'Location' && pattern.Location === filter.Name))
224
+ );
225
+ this.filteredAntiPatterns = this.filteredAntiPatterns.filter(pattern =>
226
+ locationFilters.some(filter => (filter.Type === 'Location' && pattern.Location === filter.Name))
227
+ );
228
+ }
229
+ if (productAreaFilters.length > 0) {
230
+ this.filteredPatterns = this.filteredPatterns.filter(pattern =>
231
+ productAreaFilters.some(filter => (filter.Type === 'ProductArea' && pattern.ProductArea === filter.Name))
232
+ );
233
+ this.filteredAntiPatterns = this.filteredAntiPatterns.filter(pattern =>
234
+ productAreaFilters.some(filter => (filter.Type === 'ProductArea' && pattern.ProductArea === filter.Name))
235
+ );
236
+ }
237
+ this.isLoading = false;
238
+
239
+ // and we want to the search to be reductive as well so only check filterd array
240
+ if (this._keywordFilter.length > 0) {
241
+ this.filteredPatterns = this.filteredPatterns.filter(pattern =>
242
+ pattern.Name?.toLowerCase().includes(this._keywordFilter.toLowerCase()) ||
243
+ pattern.Description.toLowerCase().includes(this._keywordFilter.toLowerCase()) ||
244
+ pattern.Location?.toLowerCase().includes(this._keywordFilter.toLowerCase()) ||
245
+ pattern.Dimension?.toLowerCase().includes(this._keywordFilter.toLowerCase()) ||
246
+ pattern.Consideration?.toLowerCase().includes(this._keywordFilter.toLowerCase())
247
+ );
248
+
249
+ this.filteredAntiPatterns = this.filteredAntiPatterns.filter(ap =>
250
+ ap.Name?.toLowerCase().includes(this._keywordFilter.toLowerCase()) ||
251
+ ap.Description.toLowerCase().includes(this._keywordFilter.toLowerCase()) ||
252
+ ap.Location?.toLowerCase().includes(this._keywordFilter.toLowerCase()) ||
253
+ ap.Dimension?.toLowerCase().includes(this._keywordFilter.toLowerCase()) ||
254
+ ap.Consideration?.toLowerCase().includes(this._keywordFilter.toLowerCase())
255
+ );
256
+ }
257
+
258
+ this.currentPageIndex = 0;
259
+ this.udpateSearchParams();
260
+
261
+ } catch (error: any) {
262
+ console.error("An error occurred applying the filters:", error?.message || String(error));
263
+ }
264
+ }
265
+
266
+ checkURLParams() {
267
+ // Load filters from URL params
268
+ const url = new URL(window.location.href.replace('#', ''));
269
+ const params = url.searchParams;
270
+ for (const [key, value] of params.entries()) {
271
+ switch (key) {
272
+ case 'Trusted':
273
+ case 'Easy':
274
+ case 'Adaptable':
275
+ case 'Location':
276
+ case 'ProductArea':
277
+ this.selectedFilters.push({ Type: key, Name: value });
278
+ this.setDimensionOption(key, value, true);
279
+ break;
280
+ case 'keywords':
281
+ this._keywordFilter = value;
282
+ break;
283
+ default:
284
+ break;
285
+ }
286
+ };
287
+ }
288
+
289
+ udpateSearchParams() {
290
+ try {
291
+ // Update page state so that we track filters in URL params
292
+ const params = new URLSearchParams();
293
+
294
+ this.selectedFilters.forEach((filter) => {
295
+ params.append(filter.Type, filter.Name);
296
+ });
297
+
298
+ if (this._keywordFilter.length > 0 && this._keywordFilter !== '')
299
+ params.set('keywords', this._keywordFilter);
300
+
301
+ const paramsString = params.toString();
302
+ let updatedUrl = window.location.pathname;
303
+
304
+ if (paramsString)
305
+ updatedUrl += `?${paramsString}`;
306
+
307
+ history.replaceState(history.state, document.title, updatedUrl);
308
+ this.shareUrl = `${window.location.protocol}//${window.location.hostname}${updatedUrl}`;
309
+
310
+ } catch (error: any) {
311
+ console.error("An error occured applying the url params:", error?.message || String(error));
312
+ }
313
+ }
314
+
315
+ handleResetFiltersClick() {
316
+ this.selectedFilters = [] as Filter[];
317
+ this._keywordFilter = '';
318
+ this.locationsArr.forEach(loc => loc.isDisabled = false);
319
+ this.productAreasArr.forEach(area => area.isDisabled = false);
320
+ this.trustedArr.forEach(behavior => behavior.Dimensions.forEach(dim => dim.isDisabled = false));
321
+ this.easyArr.forEach(behavior => behavior.Dimensions.forEach(dim => dim.isDisabled = false));
322
+ this.adaptableArr.forEach(behavior => behavior.Dimensions.forEach(dim => dim.isDisabled = false));
323
+ this.applyFilters();
324
+ }
325
+
326
+ setDimensionOption(dropDown: string, itemToDisable: string, state: boolean) {
327
+
328
+ switch (dropDown) {
329
+ case 'ProductArea':
330
+ this.productAreasArr = this.productAreasArr.map(area => area.Name === itemToDisable ? { ...area, isDisabled: state } : area);
331
+ break;
332
+ case 'Location':
333
+ this.locationsArr = this.locationsArr.map(location => location.Name === itemToDisable ? { ...location, isDisabled: state } : location);
334
+ break;
335
+ case 'Trusted':
336
+ this.trustedArr = this.trustedArr.map(behavior => ({
337
+ ...behavior,
338
+ Dimensions: behavior.Dimensions.map(dimension => dimension.Name === itemToDisable ? { ...dimension, isDisabled: state } : dimension)
339
+ }));
340
+ break;
341
+ case 'Easy':
342
+ this.easyArr = this.easyArr.map(behavior => ({
343
+ ...behavior,
344
+ Dimensions: behavior.Dimensions.map(dimension => dimension.Name === itemToDisable ? { ...dimension, isDisabled: state } : dimension)
345
+ }));
346
+ break;
347
+ case 'Adaptable':
348
+ this.adaptableArr = this.adaptableArr.map(behavior => ({
349
+ ...behavior,
350
+ Dimensions: behavior.Dimensions.map(dimension => dimension.Name === itemToDisable ? { ...dimension, isDisabled: state } : dimension)
351
+ }));
352
+ }
353
+ }
354
+
355
+ //#endregion END FILTER FUNCTIONS
356
+
357
+ //#region PAGINATION FUNCTIONS
358
+
359
+ private handlePageSizeChange(event: CustomEvent) {
360
+ this.pageSize = parseInt(event.detail, 10);
361
+ this.applyFilters();
362
+ }
363
+
364
+ private handlePreviousPageClick() {
365
+ if (this.currentPageIndex > 0) {
366
+ this.currentPageIndex--;
367
+ }
368
+ }
369
+
370
+ private handleNextPageClick() {
371
+ if (this.currentPageIndex < this.totalPages - 1) {
372
+ this.currentPageIndex++;
373
+ }
374
+ }
375
+
376
+ private get filterStatsLabel(): string {
377
+ const filteredItemCount = (this.activeTab == 'pattern') ? this.filteredPatterns.length : this.filteredAntiPatterns.length;
378
+ const allItemCount = (this.activeTab == 'pattern') ? this.allPatterns.length : this.allAntiPatterns.length;
379
+
380
+ let label;
381
+ if (filteredItemCount === allItemCount) {
382
+ label = `Showing ${allItemCount} ${this.activeTab}${allItemCount === 1 ? '' : 's'
383
+ }`;
384
+ } else {
385
+ label = `Showing ${filteredItemCount} ${this.activeTab}${filteredItemCount === 1 ? '' : 's'
386
+ }`;
387
+ }
388
+ if (this.totalPages > 1) {
389
+ label += ` • page ${this.currentPageIndex + 1} out of ${this.totalPages
390
+ }`;
391
+ }
392
+ return label;
393
+ }
394
+
395
+ private get currentPagePatterns(): Pattern[] {
396
+ const startIndex = this.currentPageIndex * this.pageSize;
397
+ return this.filteredPatterns.slice(
398
+ startIndex,
399
+ startIndex + this.pageSize
400
+ );
401
+ }
402
+
403
+ private get currentPageAntiPatterns(): Pattern[] {
404
+ const startIndex = this.currentPageIndex * this.pageSize;
405
+ return this.filteredAntiPatterns.slice(
406
+ startIndex,
407
+ startIndex + this.pageSize
408
+ );
409
+ }
410
+
411
+ private get isLastPage() {
412
+ let isActive = false;
413
+ if (this.activeTab == 'pattern') {
414
+ isActive = this.filteredPatterns.length === 0 || (this.currentPageIndex + 1) * this.pageSize >= this.filteredPatterns.length;
415
+ } else {
416
+ isActive = this.filteredAntiPatterns.length === 0 || (this.currentPageIndex + 1) * this.pageSize >= this.filteredAntiPatterns.length;
417
+ }
418
+ return isActive;
419
+ }
420
+
421
+ private get isFirstPage() {
422
+ return this.currentPageIndex === 0;
423
+ }
424
+
425
+ private get totalPages() {
426
+ let totPages = (this.activeTab == 'pattern') ? Math.ceil(this.filteredPatterns.length / this.pageSize) : Math.ceil(this.filteredAntiPatterns.length / this.pageSize);
427
+ return totPages;
428
+ }
429
+
430
+ private get activeTab() {
431
+ const tabset = this.template.querySelector('tds-tabset');
432
+ const activeTab = (tabset as any).activeTabValue;
433
+ return activeTab;
434
+ }
435
+
436
+ //#endregion PAGINATION FUNCTIONS
437
+
438
+ //#region EXPORT FUNCTIONS
439
+
440
+ loadImage(url: string) {
441
+ // Function to load an image and convert it to a base64 string
442
+ return new Promise((resolve, reject) => {
443
+ const img = new Image();
444
+ img.crossOrigin = 'Anonymous';
445
+ img.onload = () => {
446
+ let canvas = document.createElement('canvas');
447
+ canvas.width = img.width;
448
+ canvas.height = img.height;
449
+ let ctx = canvas.getContext('2d');
450
+ ctx?.drawImage(img, 0, 0);
451
+ resolve(canvas.toDataURL('image/png'));
452
+ };
453
+ img.onerror = reject;
454
+ img.src = url;
455
+ });
456
+ }
457
+
458
+ getExportFileMetaData() {
459
+ let fileName = '';
460
+ let keywords = '';
461
+ this.selectedFilters.forEach((filter) => {
462
+ fileName += `${filter.Name}_`;
463
+ keywords += `${filter.Name} `;
464
+ });
465
+ keywords = keywords.trimEnd();
466
+ fileName += (this.activeTab == 'pattern') ? `Patterns_${this.version}` : `Anti-Patterns_${this.version}`;
467
+ return { fileName, keywords };
468
+ }
469
+
470
+ async handlePdfClick() {
471
+
472
+ let fileMeta = this.getExportFileMetaData();
473
+
474
+ const margins = {
475
+ top: 20,
476
+ bottom: 20,
477
+ left: 20,
478
+ width: 522,
479
+ windowWidth: 800
480
+ };
481
+
482
+ const doc = new jsPDF('p', 'pt', 'letter');
483
+ doc.setFont('Helvetica');
484
+ doc.setFontSize(10);
485
+ doc.setProperties({
486
+ title: 'Salesforce Well-Architected Pattern & Anti-Pattern Explorer',
487
+ subject: 'Exported lists of patterns and anti-patterns',
488
+ author: 'Salesforce Architects',
489
+ keywords: 'Salesoforce, Well-Architected, ' + fileMeta.keywords,
490
+ creator: 'Salesforce Architects'
491
+ });
492
+
493
+ // set up vars for the header once
494
+ this.loadImage('/assets/images/architects_logo_horizontal.png');
495
+ const expLink = fileMeta.keywords.replaceAll(' ', ' | ');
496
+ const expLinkWidth = doc.getTextWidth(expLink);
497
+ const pageWidth = doc.internal.pageSize.width;
498
+ const expLinkXPosition = pageWidth - expLinkWidth - margins.left;
499
+
500
+ const header = (doc: any) => {
501
+ // Add header content, e.g., a title or an image
502
+ if (this.logoImageData) {
503
+ doc.addImage(this.logoImageData, 'png', margins.top, margins.left, 200, 19);
504
+ doc.setTextColor("0070d2");
505
+ doc.textWithLink(expLink, expLinkXPosition, margins.top, {
506
+ url: window.location.href
507
+ });
508
+ }
509
+ };
510
+
511
+ // get the up footer vars once
512
+ const pageHeight = doc.internal.pageSize.height;
513
+
514
+ const footer = (doc: any) => {
515
+
516
+ // link to the release page
517
+ doc.setTextColor("0070d2");
518
+ doc.textWithLink(`Release (${this.version})`, margins.left, pageHeight - margins.bottom, {
519
+ url: "https://architect.salesforce.com/releases/"
520
+ });
521
+
522
+ // get the page count and formatting
523
+ const pageCount = `Page ${doc.getNumberOfPages()}`;
524
+ const pageCountTextWidth = doc.getTextWidth(pageCount);
525
+ const pageCountXPosition = pageWidth - pageCountTextWidth - margins.left;
526
+ // add a page count before changing color
527
+ doc.setTextColor("000000");
528
+ doc.text(pageCount, pageCountXPosition, pageHeight - margins.bottom);
529
+ };
530
+
531
+ doc.internal.events.subscribe('addPage', () => {
532
+ header(doc);
533
+ footer(doc);
534
+ });
535
+
536
+ // add the initial header and footer
537
+ header(doc);
538
+ footer(doc);
539
+
540
+ const htmlOptions = {
541
+ margin: [margins.top * 2.5, margins.left, margins.bottom * 2, margins.left],
542
+ autoPaging: true,
543
+ x: margins.left,
544
+ y: margins.top,
545
+ width: margins.width,
546
+ windowWidth: margins.windowWidth
547
+ };
548
+
549
+ const htmlTable = (this.activeTab == 'pattern') ? this.makeHTMLTable('What Good Looks Like<p>Pattern</p>', this.filteredPatterns) : this.makeHTMLTable('What to Avoid<p>Anti-Pattern</p>', this.filteredAntiPatterns);
550
+
551
+ await this.addHtmlToPdf(doc, htmlTable, htmlOptions);
552
+ htmlOptions.y = doc.internal.pageSize.getHeight() * doc.internal.pages.length;
553
+
554
+ // below if we want them in the same doc
555
+ // doc.addPage();
556
+ //await this.addHtmlToPdf(doc, antipatternsHtml, htmlOptions);
557
+
558
+ doc.save(`${fileMeta.fileName}.pdf`);
559
+
560
+ }
561
+
562
+ addHtmlToPdf(doc: any, htmlContent: string, options: any = {}) {
563
+ return new Promise((resolve) => {
564
+ doc.html(htmlContent, {
565
+ ...options,
566
+ callback: function (doc: any) {
567
+ resolve(doc);
568
+ }
569
+ });
570
+ });
571
+ }
572
+
573
+ makeHTMLTable(tableName: string, tableArr: any[]) {
574
+ let htmlTable = `
575
+ <table width="100%" style="font-family:Helvetica; border-collapse: collapse;">
576
+ <colgroup>
577
+ <col width="44%">
578
+ <col width="26%">
579
+ <col width="30%">
580
+ </colgroup>
581
+ <thead>
582
+ <tr>
583
+ <th style="background-color: #ebf5ff; border: 1px solid #dddbda; text-align: left; padding: 10px; vertical-align: middle;">${tableName}</th>
584
+ <th style="background-color: #ebf5ff; border: 1px solid #dddbda; text-align: left; padding: 10px; vertical-align: middle;">Where to Look<p>Product Area | Location</p></th>
585
+ <th style="background-color: #ebf5ff; border: 1px solid #dddbda; text-align: left; padding: 10px; vertical-align: middle;">Learn More <p>Dimension | Consideration</p></th>
586
+ </tr>
587
+ </thead>
588
+ <tbody>`;
589
+
590
+ tableArr.forEach((pattern: any, index: number) => {
591
+ const backgroundColor = (index % 2 === 0) ? '#fafaf9' : '#ffffff'; // Add background color to even rows
592
+ const description = (typeof pattern.Name === 'undefined' || pattern.Name === null || pattern.Name === '') ? pattern.Description : `${pattern.Name}<br/>${pattern.Description}`;
593
+
594
+ htmlTable += `<tr style="background-color: ${backgroundColor}">
595
+ <td style="border: 1px solid #dddbda; text-align: left; padding: 10px;">
596
+ ${description}
597
+ </td>
598
+ <td style="border: 1px solid #dddbda; text-align: left; padding: 10px;">
599
+ ${pattern.ProductArea} | In your ${pattern.Location}
600
+ </td>
601
+ <td style="border: 1px solid #dddbda; text-align: left; padding: 10px;">
602
+ ${pattern.Dimension} | ${pattern.Consideration}
603
+ </td>
604
+ </tr>`;
605
+ });
606
+ htmlTable += `</tbody></table>`;
607
+ return htmlTable;
608
+ }
609
+
610
+ async handleCsvClick() {
611
+
612
+ let fileMeta = this.getExportFileMetaData()
613
+
614
+ if (this.activeTab == 'pattern') {
615
+ this.exportToCSV('What Good Looks Like,Where to Look,Learn More','Pattern,Product Area | Location,Dimension | Consideration' , this.filteredPatterns, fileMeta.fileName);
616
+ } else {
617
+ this.exportToCSV('What to Avoid,Where to Look,Learn More','Anti-Pattern,Product Area | Location,Dimension | Consideration',this.filteredAntiPatterns, fileMeta.fileName);
618
+ }
619
+
620
+ }
621
+
622
+ exportToCSV(headers: string, subheaders: string, patArray: any[], filename: string) {
623
+ // Convert Array to CSV
624
+ const csv: String[] = [];
625
+ csv.push(headers); // Add headers row
626
+ csv.push(subheaders);
627
+ patArray.forEach(pattern => {
628
+
629
+ let row: String[] = [];
630
+ const description = (typeof pattern.Name === 'undefined' || pattern.Name === '') ? pattern.Description : `${pattern.Name} ${pattern.Description}`;
631
+ row.push(this.escapeCSVField(description));
632
+ row.push(this.escapeCSVField(`${pattern.ProductArea} | ${pattern.Location}`));
633
+ row.push(this.escapeCSVField(`${pattern.Dimension} | ${pattern.Consideration}`));
634
+
635
+ csv.push(row.join(","));
636
+
637
+ });
638
+
639
+ const csvString = csv.join('\n');
640
+
641
+ // Create Blob and Download Link
642
+ const blob = new Blob([csvString], { type: 'text/csv;charset=utf-8;' });
643
+ const link = document.createElement('a');
644
+ link.href = URL.createObjectURL(blob);
645
+ link.download = `${filename}.csv`;
646
+ document.body.appendChild(link);
647
+ link.click();
648
+ document.body.removeChild(link);
649
+
650
+ }
651
+
652
+ escapeCSVField(field: string) {
653
+ if (field.includes(',') || field.includes('"') || field.includes('\n')) {
654
+ // Escape double quotes
655
+ field = field.replace(/"/g, '""');
656
+ // Enclose field in double quotes
657
+ field = `"${field}"`;
658
+ }
659
+ return field;
660
+ }
661
+
662
+ //#endregion EXPORT FUNCTIONS
663
+
664
+ }