@openedx/frontend-base 1.0.0-alpha.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (356) hide show
  1. package/LICENSE +661 -0
  2. package/README.md +112 -0
  3. package/config/babel/babel.config.js +28 -0
  4. package/config/config-helpers/createConfig.js +13 -0
  5. package/config/config-helpers/createLintConfig.js +16 -0
  6. package/config/config-helpers/getBaseConfig.js +12 -0
  7. package/config/defaultConfigPaths.js +35 -0
  8. package/config/eslint/base.eslint.config.js +113 -0
  9. package/config/index.js +12 -0
  10. package/config/jest/jest.config.js +30 -0
  11. package/config/tsconfig.json +32 -0
  12. package/config/types.js +25 -0
  13. package/config/webpack/common-config/all/getCodeRules.js +52 -0
  14. package/config/webpack/common-config/all/getFileLoaderRules.js +26 -0
  15. package/config/webpack/common-config/all/getIgnoreWarnings.js +14 -0
  16. package/config/webpack/common-config/all/getImageMinimizer.js +25 -0
  17. package/config/webpack/common-config/all/getStylesheetRule.js +112 -0
  18. package/config/webpack/common-config/dev/getDevServer.js +38 -0
  19. package/config/webpack/common-config/index.js +18 -0
  20. package/config/webpack/common-config/site/getHtmlWebpackPlugin.js +16 -0
  21. package/config/webpack/plugins/html-webpack-new-relic-plugin/HtmlWebpackNewRelicPlugin.js +91 -0
  22. package/config/webpack/plugins/html-webpack-new-relic-plugin/index.js +7 -0
  23. package/config/webpack/plugins/html-webpack-new-relic-plugin/test/fixtures/entry.js +3 -0
  24. package/config/webpack/plugins/paragon-webpack-plugin/ParagonWebpackPlugin.js +108 -0
  25. package/config/webpack/plugins/paragon-webpack-plugin/index.js +7 -0
  26. package/config/webpack/plugins/paragon-webpack-plugin/utils/assetUtils.js +64 -0
  27. package/config/webpack/plugins/paragon-webpack-plugin/utils/htmlUtils.js +53 -0
  28. package/config/webpack/plugins/paragon-webpack-plugin/utils/index.js +9 -0
  29. package/config/webpack/plugins/paragon-webpack-plugin/utils/paragonStylesheetUtils.js +114 -0
  30. package/config/webpack/plugins/paragon-webpack-plugin/utils/scriptUtils.js +146 -0
  31. package/config/webpack/plugins/paragon-webpack-plugin/utils/stylesheetUtils.js +126 -0
  32. package/config/webpack/plugins/paragon-webpack-plugin/utils/tagUtils.js +57 -0
  33. package/config/webpack/types.js +2 -0
  34. package/config/webpack/utils/getLocalAliases.js +65 -0
  35. package/config/webpack/utils/getPublicPath.js +6 -0
  36. package/config/webpack/utils/getResolvedSiteConfigPath.js +32 -0
  37. package/config/webpack/utils/paragonUtils.js +138 -0
  38. package/config/webpack/webpack.config.build.js +80 -0
  39. package/config/webpack/webpack.config.dev.js +76 -0
  40. package/config/webpack/webpack.config.dev.shell.js +110 -0
  41. package/eslint.config.js +18 -0
  42. package/frontend-base.d.ts +8 -0
  43. package/index.ts +7 -0
  44. package/jest.config.js +7 -0
  45. package/openedx-frontend-base.tgz +0 -0
  46. package/package.json +149 -0
  47. package/runtime/analytics/MockAnalyticsService.js +71 -0
  48. package/runtime/analytics/SegmentAnalyticsService.js +243 -0
  49. package/runtime/analytics/index.ts +12 -0
  50. package/runtime/analytics/interface.js +145 -0
  51. package/runtime/auth/AxiosCsrfTokenService.js +60 -0
  52. package/runtime/auth/AxiosJwtAuthService.js +363 -0
  53. package/runtime/auth/AxiosJwtTokenService.js +134 -0
  54. package/runtime/auth/LocalForageCache.js +76 -0
  55. package/runtime/auth/MockAuthService.js +278 -0
  56. package/runtime/auth/index.ts +19 -0
  57. package/runtime/auth/interceptors/createCsrfTokenProviderInterceptor.js +36 -0
  58. package/runtime/auth/interceptors/createJwtTokenProviderInterceptor.js +37 -0
  59. package/runtime/auth/interceptors/createProcessAxiosRequestErrorInterceptor.js +20 -0
  60. package/runtime/auth/interceptors/createRetryInterceptor.js +74 -0
  61. package/runtime/auth/interface.js +309 -0
  62. package/runtime/auth/utils.js +105 -0
  63. package/runtime/babel.config.js +3 -0
  64. package/runtime/config/index.ts +295 -0
  65. package/runtime/constants.ts +68 -0
  66. package/runtime/i18n/index.js +118 -0
  67. package/runtime/i18n/injectIntlWithShim.jsx +48 -0
  68. package/runtime/i18n/lib.ts +272 -0
  69. package/runtime/index.ts +134 -0
  70. package/runtime/initialize.js +352 -0
  71. package/runtime/jest.config.js +32 -0
  72. package/runtime/logging/MockLoggingService.js +31 -0
  73. package/runtime/logging/NewRelicLoggingService.js +184 -0
  74. package/runtime/logging/index.ts +9 -0
  75. package/runtime/logging/interface.js +109 -0
  76. package/runtime/logging/types.ts +4 -0
  77. package/runtime/react/AuthenticatedPageRoute.jsx +43 -0
  78. package/runtime/react/CombinedAppProvider.tsx +46 -0
  79. package/runtime/react/CurrentAppContext.tsx +25 -0
  80. package/runtime/react/CurrentAppProvider.tsx +46 -0
  81. package/runtime/react/Divider.tsx +5 -0
  82. package/runtime/react/ErrorBoundary.jsx +47 -0
  83. package/runtime/react/ErrorPage.jsx +72 -0
  84. package/runtime/react/LoginRedirect.jsx +16 -0
  85. package/runtime/react/PageWrap.jsx +24 -0
  86. package/runtime/react/SiteContext.tsx +32 -0
  87. package/runtime/react/SiteProvider.tsx +78 -0
  88. package/runtime/react/hooks.ts +106 -0
  89. package/runtime/react/index.ts +19 -0
  90. package/runtime/routing/index.ts +1 -0
  91. package/runtime/routing/utils.ts +34 -0
  92. package/runtime/scripts/GoogleAnalyticsLoader.ts +59 -0
  93. package/runtime/scripts/index.ts +1 -0
  94. package/runtime/setupTest.js +49 -0
  95. package/runtime/slots/Slot.tsx +32 -0
  96. package/runtime/slots/SlotContext.tsx +8 -0
  97. package/runtime/slots/hooks.ts +35 -0
  98. package/runtime/slots/index.ts +7 -0
  99. package/runtime/slots/layout/DefaultSlotLayout.tsx +9 -0
  100. package/runtime/slots/layout/hooks.ts +65 -0
  101. package/runtime/slots/layout/index.ts +5 -0
  102. package/runtime/slots/layout/types.ts +45 -0
  103. package/runtime/slots/layout/utils.ts +14 -0
  104. package/runtime/slots/types.ts +23 -0
  105. package/runtime/slots/utils.ts +59 -0
  106. package/runtime/slots/widget/WidgetContext.tsx +9 -0
  107. package/runtime/slots/widget/WidgetProvider.tsx +30 -0
  108. package/runtime/slots/widget/hooks.ts +105 -0
  109. package/runtime/slots/widget/iframe/IFrameContentWrapper.messages.tsx +16 -0
  110. package/runtime/slots/widget/iframe/IFrameContentWrapper.tsx +84 -0
  111. package/runtime/slots/widget/iframe/IFrameWidget.tsx +59 -0
  112. package/runtime/slots/widget/iframe/constants.ts +19 -0
  113. package/runtime/slots/widget/iframe/hooks.ts +179 -0
  114. package/runtime/slots/widget/iframe/index.ts +6 -0
  115. package/runtime/slots/widget/iframe/types.ts +7 -0
  116. package/runtime/slots/widget/index.ts +6 -0
  117. package/runtime/slots/widget/types.ts +134 -0
  118. package/runtime/slots/widget/utils.tsx +201 -0
  119. package/runtime/subscriptions.ts +60 -0
  120. package/runtime/testing/index.ts +9 -0
  121. package/runtime/testing/initializeMockApp.ts +81 -0
  122. package/runtime/testing/mockMessages.ts +23 -0
  123. package/runtime/utils.js +178 -0
  124. package/shell/DefaultLayout.tsx +18 -0
  125. package/shell/DefaultMain.tsx +7 -0
  126. package/shell/Logo.tsx +28 -0
  127. package/shell/Shell.messages.ts +61 -0
  128. package/shell/Shell.tsx +18 -0
  129. package/shell/app.scss +149 -0
  130. package/shell/app.ts +24 -0
  131. package/shell/babel.config.js +3 -0
  132. package/shell/dev/devFooter/app.tsx +43 -0
  133. package/shell/dev/devFooter/index.ts +1 -0
  134. package/shell/dev/devHeader/BarContext.tsx +13 -0
  135. package/shell/dev/devHeader/BarLink.tsx +16 -0
  136. package/shell/dev/devHeader/BarProvider.tsx +25 -0
  137. package/shell/dev/devHeader/CoursesLink.tsx +16 -0
  138. package/shell/dev/devHeader/FooContext.tsx +13 -0
  139. package/shell/dev/devHeader/FooLink.tsx +16 -0
  140. package/shell/dev/devHeader/FooProvider.tsx +25 -0
  141. package/shell/dev/devHeader/app.tsx +53 -0
  142. package/shell/dev/devHeader/index.ts +1 -0
  143. package/shell/dev/devHeader/providers.tsx +11 -0
  144. package/shell/dev/devHome/HomePage.tsx +28 -0
  145. package/shell/dev/devHome/app.ts +18 -0
  146. package/shell/dev/devHome/i18n/index.ts +27 -0
  147. package/shell/dev/devHome/index.ts +1 -0
  148. package/shell/dev/devHome/messages.ts +11 -0
  149. package/shell/dev/devUser/app.tsx +24 -0
  150. package/shell/dev/devUser/index.ts +1 -0
  151. package/shell/dev/index.ts +5 -0
  152. package/shell/dev/slotShowcase/HorizontalSlotLayout.tsx +11 -0
  153. package/shell/dev/slotShowcase/LayoutWithOptions.tsx +17 -0
  154. package/shell/dev/slotShowcase/SlotShowcasePage.tsx +66 -0
  155. package/shell/dev/slotShowcase/WidgetWithOptions.tsx +11 -0
  156. package/shell/dev/slotShowcase/app.tsx +373 -0
  157. package/shell/dev/slotShowcase/index.ts +1 -0
  158. package/shell/footer/CenterLinks.tsx +11 -0
  159. package/shell/footer/CopyrightNotice.tsx +36 -0
  160. package/shell/footer/Footer.tsx +34 -0
  161. package/shell/footer/LabeledLinkColumn.tsx +19 -0
  162. package/shell/footer/LanguageMenu.tsx +35 -0
  163. package/shell/footer/LanguageMenuItem.tsx +23 -0
  164. package/shell/footer/LeftLinks.tsx +11 -0
  165. package/shell/footer/LegalNotices.tsx +17 -0
  166. package/shell/footer/PoweredBy.tsx +17 -0
  167. package/shell/footer/RevealLinks.tsx +43 -0
  168. package/shell/footer/RightLinks.tsx +11 -0
  169. package/shell/footer/app.tsx +73 -0
  170. package/shell/footer/data/api.ts +48 -0
  171. package/shell/footer/index.ts +2 -0
  172. package/shell/header/AuthenticatedMenu.tsx +32 -0
  173. package/shell/header/Header.tsx +17 -0
  174. package/shell/header/anonymous-menu/AnonymousMenu.tsx +14 -0
  175. package/shell/header/anonymous-menu/LoginButton.tsx +14 -0
  176. package/shell/header/anonymous-menu/RegisterButton.tsx +15 -0
  177. package/shell/header/app.tsx +142 -0
  178. package/shell/header/desktop/DesktopLayout.tsx +22 -0
  179. package/shell/header/desktop/PrimaryNavLinks.tsx +10 -0
  180. package/shell/header/desktop/SecondaryNavLinks.tsx +10 -0
  181. package/shell/header/index.ts +2 -0
  182. package/shell/header/mobile/MobileLayout.tsx +47 -0
  183. package/shell/header/mobile/MobileNavLinks.tsx +10 -0
  184. package/shell/i18n/index.ts +25 -0
  185. package/shell/index.ts +7 -0
  186. package/shell/jest.config.js +30 -0
  187. package/shell/menus/LinkMenuItem.tsx +64 -0
  188. package/shell/menus/NavDropdownMenuSlot.tsx +29 -0
  189. package/shell/menus/ProfileLinkMenuItem.tsx +33 -0
  190. package/shell/menus/data/utils.ts +19 -0
  191. package/shell/public/index.html +10 -0
  192. package/shell/router/createRouter.ts +17 -0
  193. package/shell/router/getAppRoutes.ts +21 -0
  194. package/shell/setupTest.js +48 -0
  195. package/shell/site.config.dev.tsx +49 -0
  196. package/shell/site.tsx +41 -0
  197. package/test-site/app.d.ts +15 -0
  198. package/test-site/dist/176.436443549ebb858db483.js +2 -0
  199. package/test-site/dist/176.436443549ebb858db483.js.map +1 -0
  200. package/test-site/dist/362.536eff787d2380fe246c.js +2 -0
  201. package/test-site/dist/362.536eff787d2380fe246c.js.map +1 -0
  202. package/test-site/dist/653.486966b108d224551296.js +2 -0
  203. package/test-site/dist/653.486966b108d224551296.js.map +1 -0
  204. package/test-site/dist/74e025d3fe9a7b7f8503054e2563b353.jpg +0 -0
  205. package/test-site/dist/806.323cf6496ad0a7fe73a7.js +3 -0
  206. package/test-site/dist/806.323cf6496ad0a7fe73a7.js.LICENSE.txt +106 -0
  207. package/test-site/dist/806.323cf6496ad0a7fe73a7.js.map +1 -0
  208. package/test-site/dist/95ec738c0b7faac5b5c9126794446bbd.svg +4 -0
  209. package/test-site/dist/app.612058b36c74787759ac.css +61 -0
  210. package/test-site/dist/app.612058b36c74787759ac.css.map +1 -0
  211. package/test-site/dist/app.612058b36c74787759ac.js +2 -0
  212. package/test-site/dist/app.612058b36c74787759ac.js.map +1 -0
  213. package/test-site/dist/cb28cdb1468c915e27e5cec9af64f22f.svg +1 -0
  214. package/test-site/dist/index.html +1 -0
  215. package/test-site/dist/report.html +39 -0
  216. package/test-site/dist/runtime.c7aeaf7b967496cb076f.js +2 -0
  217. package/test-site/dist/runtime.c7aeaf7b967496cb076f.js.map +1 -0
  218. package/test-site/eslint.config.js +12 -0
  219. package/test-site/package-lock.json +19226 -0
  220. package/test-site/package.json +29 -0
  221. package/test-site/public/index.html +10 -0
  222. package/test-site/site.config.build.tsx +27 -0
  223. package/test-site/site.config.dev.tsx +27 -0
  224. package/test-site/src/authenticated-page/AuthenticatedPage.tsx +18 -0
  225. package/test-site/src/authenticated-page/i18n/index.ts +27 -0
  226. package/test-site/src/authenticated-page/index.tsx +28 -0
  227. package/test-site/src/example-page/ExamplePage.tsx +79 -0
  228. package/test-site/src/example-page/Image.tsx +11 -0
  229. package/test-site/src/example-page/ParagonPreview.jsx +66 -0
  230. package/test-site/src/example-page/apple.jpg +0 -0
  231. package/test-site/src/example-page/apple.svg +1 -0
  232. package/test-site/src/example-page/index.ts +16 -0
  233. package/test-site/src/i18n/README.md +3 -0
  234. package/test-site/src/i18n/messages/frontend-app-sample/ar.json +4 -0
  235. package/test-site/src/i18n/messages/frontend-app-sample/eo.json +1 -0
  236. package/test-site/src/i18n/messages/frontend-app-sample/es_419.json +4 -0
  237. package/test-site/src/i18n/messages/frontend-component-emptylangs/ar.json +1 -0
  238. package/test-site/src/i18n/messages/frontend-component-singlelang/ar.json +3 -0
  239. package/test-site/src/iframe-widget/IframeWidget.tsx +14 -0
  240. package/test-site/src/iframe-widget/index.ts +16 -0
  241. package/test-site/src/index.tsx +3 -0
  242. package/test-site/src/messages.js +11 -0
  243. package/test-site/src/site.scss +11 -0
  244. package/test-site/tsconfig.json +14 -0
  245. package/tools/babel/babel.config.js +27 -0
  246. package/tools/babel.config.js +3 -0
  247. package/tools/cli/README.md +29 -0
  248. package/tools/cli/commands/pack.ts +9 -0
  249. package/tools/cli/commands/release.ts +27 -0
  250. package/tools/cli/commands/serve.ts +43 -0
  251. package/tools/cli/intl-imports.ts +274 -0
  252. package/tools/cli/openedx.ts +101 -0
  253. package/tools/cli/transifex-utils.ts +75 -0
  254. package/tools/cli/utils/ensureConfigFilenameOption.ts +40 -0
  255. package/tools/cli/utils/formatter.ts +10 -0
  256. package/tools/cli/utils/getResolvedConfigPath.ts +23 -0
  257. package/tools/cli/utils/prettyPrintTitle.ts +15 -0
  258. package/tools/cli/utils/printUsage.ts +53 -0
  259. package/tools/config-helpers/createConfig.ts +8 -0
  260. package/tools/config-helpers/createLintConfig.ts +14 -0
  261. package/tools/config-helpers/getBaseConfig.ts +11 -0
  262. package/tools/defaultConfigPaths.ts +30 -0
  263. package/tools/dist/babel/babel.config.js +28 -0
  264. package/tools/dist/cli/commands/pack.js +14 -0
  265. package/tools/dist/cli/commands/release.js +28 -0
  266. package/tools/dist/cli/commands/serve.js +44 -0
  267. package/tools/dist/cli/intl-imports.js +233 -0
  268. package/tools/dist/cli/openedx.js +100 -0
  269. package/tools/dist/cli/transifex-utils.js +68 -0
  270. package/tools/dist/cli/utils/ensureConfigFilenameOption.js +42 -0
  271. package/tools/dist/cli/utils/formatter.js +10 -0
  272. package/tools/dist/cli/utils/getResolvedConfigPath.js +28 -0
  273. package/tools/dist/cli/utils/prettyPrintTitle.js +17 -0
  274. package/tools/dist/cli/utils/printUsage.js +48 -0
  275. package/tools/dist/config-helpers/createConfig.js +13 -0
  276. package/tools/dist/config-helpers/createLintConfig.js +16 -0
  277. package/tools/dist/config-helpers/getBaseConfig.js +12 -0
  278. package/tools/dist/defaultConfigPaths.js +35 -0
  279. package/tools/dist/eslint/base.eslint.config.js +113 -0
  280. package/tools/dist/eslint.config.js +11 -0
  281. package/tools/dist/index.js +12 -0
  282. package/tools/dist/jest/jest.config.js +30 -0
  283. package/tools/dist/jest.config.js +20 -0
  284. package/tools/dist/types.js +25 -0
  285. package/tools/dist/typescript/tsconfig.json +32 -0
  286. package/tools/dist/webpack/common-config/all/getCodeRules.js +52 -0
  287. package/tools/dist/webpack/common-config/all/getFileLoaderRules.js +26 -0
  288. package/tools/dist/webpack/common-config/all/getIgnoreWarnings.js +14 -0
  289. package/tools/dist/webpack/common-config/all/getImageMinimizer.js +25 -0
  290. package/tools/dist/webpack/common-config/all/getStylesheetRule.js +112 -0
  291. package/tools/dist/webpack/common-config/dev/getDevServer.js +38 -0
  292. package/tools/dist/webpack/common-config/index.js +18 -0
  293. package/tools/dist/webpack/common-config/site/getHtmlWebpackPlugin.js +16 -0
  294. package/tools/dist/webpack/plugins/html-webpack-new-relic-plugin/HtmlWebpackNewRelicPlugin.js +91 -0
  295. package/tools/dist/webpack/plugins/html-webpack-new-relic-plugin/index.js +7 -0
  296. package/tools/dist/webpack/plugins/html-webpack-new-relic-plugin/test/fixtures/entry.js +3 -0
  297. package/tools/dist/webpack/plugins/paragon-webpack-plugin/ParagonWebpackPlugin.js +108 -0
  298. package/tools/dist/webpack/plugins/paragon-webpack-plugin/index.js +7 -0
  299. package/tools/dist/webpack/plugins/paragon-webpack-plugin/utils/assetUtils.js +64 -0
  300. package/tools/dist/webpack/plugins/paragon-webpack-plugin/utils/htmlUtils.js +53 -0
  301. package/tools/dist/webpack/plugins/paragon-webpack-plugin/utils/index.js +9 -0
  302. package/tools/dist/webpack/plugins/paragon-webpack-plugin/utils/paragonStylesheetUtils.js +114 -0
  303. package/tools/dist/webpack/plugins/paragon-webpack-plugin/utils/scriptUtils.js +146 -0
  304. package/tools/dist/webpack/plugins/paragon-webpack-plugin/utils/stylesheetUtils.js +126 -0
  305. package/tools/dist/webpack/plugins/paragon-webpack-plugin/utils/tagUtils.js +57 -0
  306. package/tools/dist/webpack/types.js +2 -0
  307. package/tools/dist/webpack/utils/getLocalAliases.js +65 -0
  308. package/tools/dist/webpack/utils/getPublicPath.js +6 -0
  309. package/tools/dist/webpack/utils/getResolvedSiteConfigPath.js +32 -0
  310. package/tools/dist/webpack/utils/paragonUtils.js +138 -0
  311. package/tools/dist/webpack/webpack.config.build.js +80 -0
  312. package/tools/dist/webpack/webpack.config.dev.js +76 -0
  313. package/tools/dist/webpack/webpack.config.dev.shell.js +110 -0
  314. package/tools/eslint/base.eslint.config.js +124 -0
  315. package/tools/eslint/modules.d.ts +5 -0
  316. package/tools/eslint.config.js +15 -0
  317. package/tools/index.ts +3 -0
  318. package/tools/jest/jest.config.js +30 -0
  319. package/tools/jest.config.js +19 -0
  320. package/tools/tsconfig.json +24 -0
  321. package/tools/types.ts +21 -0
  322. package/tools/typescript/tsconfig.json +32 -0
  323. package/tools/webpack/common-config/README.md +15 -0
  324. package/tools/webpack/common-config/all/getCodeRules.ts +51 -0
  325. package/tools/webpack/common-config/all/getFileLoaderRules.ts +23 -0
  326. package/tools/webpack/common-config/all/getIgnoreWarnings.ts +13 -0
  327. package/tools/webpack/common-config/all/getImageMinimizer.ts +26 -0
  328. package/tools/webpack/common-config/all/getStylesheetRule.ts +111 -0
  329. package/tools/webpack/common-config/dev/getDevServer.ts +35 -0
  330. package/tools/webpack/common-config/index.ts +6 -0
  331. package/tools/webpack/common-config/site/getHtmlWebpackPlugin.ts +11 -0
  332. package/tools/webpack/modules.d.ts +6 -0
  333. package/tools/webpack/plugins/html-webpack-new-relic-plugin/HtmlWebpackNewRelicPlugin.ts +102 -0
  334. package/tools/webpack/plugins/html-webpack-new-relic-plugin/LICENSE +21 -0
  335. package/tools/webpack/plugins/html-webpack-new-relic-plugin/README.md +7 -0
  336. package/tools/webpack/plugins/html-webpack-new-relic-plugin/index.js +3 -0
  337. package/tools/webpack/plugins/html-webpack-new-relic-plugin/test/fixtures/entry.js +1 -0
  338. package/tools/webpack/plugins/paragon-webpack-plugin/ParagonWebpackPlugin.ts +134 -0
  339. package/tools/webpack/plugins/paragon-webpack-plugin/index.ts +3 -0
  340. package/tools/webpack/plugins/paragon-webpack-plugin/utils/assetUtils.ts +71 -0
  341. package/tools/webpack/plugins/paragon-webpack-plugin/utils/htmlUtils.ts +72 -0
  342. package/tools/webpack/plugins/paragon-webpack-plugin/utils/index.ts +6 -0
  343. package/tools/webpack/plugins/paragon-webpack-plugin/utils/paragonStylesheetUtils.ts +131 -0
  344. package/tools/webpack/plugins/paragon-webpack-plugin/utils/scriptUtils.ts +144 -0
  345. package/tools/webpack/plugins/paragon-webpack-plugin/utils/stylesheetUtils.ts +106 -0
  346. package/tools/webpack/plugins/paragon-webpack-plugin/utils/tagUtils.ts +54 -0
  347. package/tools/webpack/types.ts +69 -0
  348. package/tools/webpack/utils/getLocalAliases.ts +65 -0
  349. package/tools/webpack/utils/getPublicPath.ts +3 -0
  350. package/tools/webpack/utils/getResolvedSiteConfigPath.ts +28 -0
  351. package/tools/webpack/utils/paragonUtils.ts +152 -0
  352. package/tools/webpack/webpack.config.build.ts +93 -0
  353. package/tools/webpack/webpack.config.dev.shell.ts +122 -0
  354. package/tools/webpack/webpack.config.dev.ts +90 -0
  355. package/tsconfig.json +23 -0
  356. package/types.ts +99 -0
@@ -0,0 +1,19 @@
1
+ import { isValidElement, ReactNode } from 'react';
2
+ import { IntlShape, MessageDescriptor } from 'react-intl';
3
+
4
+ import {
5
+ MenuItemName
6
+ } from '../../../types';
7
+ // A name can be a string or a react-intl MessageDescriptor.
8
+ export function getItemLabel(label: MenuItemName, intl: IntlShape): ReactNode {
9
+ if (typeof label === 'string') {
10
+ return label;
11
+ }
12
+
13
+ if (isValidElement(label)) {
14
+ return label;
15
+ }
16
+
17
+ // If it's not a valid element, it's a MessageDescriptor.
18
+ return intl.formatMessage(label as MessageDescriptor);
19
+ }
@@ -0,0 +1,10 @@
1
+ <!doctype html>
2
+ <html lang="en-us">
3
+ <head>
4
+ <title>Shell Development Site</title>
5
+ <link rel="shortcut icon" href="https://edx-cdn.org/v3/default/favicon.ico" type="image/x-icon" />
6
+ </head>
7
+ <body>
8
+ <div id="root"></div>
9
+ </body>
10
+ </html>
@@ -0,0 +1,17 @@
1
+ import { createBrowserRouter } from 'react-router-dom';
2
+
3
+ import { getBasename } from '../../runtime/initialize';
4
+ import Shell from '../Shell';
5
+
6
+ import getAppRoutes from './getAppRoutes';
7
+
8
+ export default function createRouter() {
9
+ return createBrowserRouter([
10
+ {
11
+ Component: Shell,
12
+ children: getAppRoutes(),
13
+ }
14
+ ], {
15
+ basename: getBasename(),
16
+ });
17
+ }
@@ -0,0 +1,21 @@
1
+ import { RouteObject } from 'react-router';
2
+
3
+ import { getSiteConfig } from '../../runtime';
4
+ import { App } from '../../types';
5
+
6
+ export default function getAppRoutes() {
7
+ const { apps } = getSiteConfig();
8
+
9
+ let routes: RouteObject[] = [];
10
+
11
+ if (apps) {
12
+ apps.forEach(
13
+ (app: App) => {
14
+ if (Array.isArray(app.routes)) {
15
+ routes = routes.concat(app.routes);
16
+ }
17
+ }
18
+ );
19
+ }
20
+ return routes;
21
+ }
@@ -0,0 +1,48 @@
1
+ import '@testing-library/jest-dom';
2
+ import siteConfig from 'site.config';
3
+ import { mergeSiteConfig } from '../runtime';
4
+
5
+ jest.mock('universal-cookie', () => {
6
+ const mCookie = {
7
+ get: jest.fn(),
8
+ remove: jest.fn(),
9
+ };
10
+ return jest.fn(() => mCookie);
11
+ });
12
+
13
+ mergeSiteConfig(siteConfig);
14
+
15
+ global.PARAGON_THEME = {
16
+ paragon: {
17
+ version: '1.0.0',
18
+ themeUrls: {
19
+ core: {
20
+ fileName: 'core.min.css',
21
+ },
22
+ defaults: {
23
+ light: 'light',
24
+ },
25
+ variants: {
26
+ light: {
27
+ fileName: 'light.min.css',
28
+ },
29
+ },
30
+ },
31
+ },
32
+ brand: {
33
+ version: '1.0.0',
34
+ themeUrls: {
35
+ core: {
36
+ fileName: 'core.min.css',
37
+ },
38
+ defaults: {
39
+ light: 'light',
40
+ },
41
+ variants: {
42
+ light: {
43
+ fileName: 'light.min.css',
44
+ },
45
+ },
46
+ },
47
+ },
48
+ };
@@ -0,0 +1,49 @@
1
+ import { EnvironmentTypes, SiteConfig } from '../types';
2
+ import { devFooterApp, devHeaderApp, devHomeApp, devUserApp, slotShowcaseApp } from './dev';
3
+ import { footerApp, headerApp, shellApp } from '.';
4
+
5
+ import './app.scss';
6
+
7
+ const siteConfig: SiteConfig = {
8
+ apps: [
9
+ shellApp,
10
+ headerApp,
11
+ footerApp,
12
+ devUserApp,
13
+ devHomeApp,
14
+ devHeaderApp,
15
+ devFooterApp,
16
+ slotShowcaseApp,
17
+ ],
18
+
19
+ externalRoutes: [
20
+ {
21
+ role: 'profile',
22
+ url: 'http://apps.local.openedx.io:1995/profile/'
23
+ },
24
+ {
25
+ role: 'account',
26
+ url: 'http://apps.local.openedx.io:1997/account/'
27
+ },
28
+ {
29
+ role: 'logout',
30
+ url: 'http://local.openedx.io:8000/logout'
31
+ },
32
+ ],
33
+
34
+ // General
35
+ siteId: 'shell',
36
+ siteName: 'My Open edX Site',
37
+ baseUrl: 'http://apps.local.openedx.io:8080',
38
+ environment: EnvironmentTypes.DEVELOPMENT,
39
+
40
+ // Frontend URLs
41
+ loginUrl: 'http://local.openedx.io:8000/login',
42
+ logoutUrl: 'http://local.openedx.io:8000/logout',
43
+
44
+ // API URLs
45
+ lmsBaseUrl: 'http://local.openedx.io:8000',
46
+ mfeConfigApiUrl: 'http://apps.local.openedx.io:8080/api/mfe_config/v1',
47
+ };
48
+
49
+ export default siteConfig;
package/shell/site.tsx ADDED
@@ -0,0 +1,41 @@
1
+ import { StrictMode } from 'react';
2
+ import { createRoot } from 'react-dom/client';
3
+ import { RouterProvider } from 'react-router-dom';
4
+ import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
5
+
6
+ import {
7
+ SITE_INIT_ERROR,
8
+ SITE_READY,
9
+ initialize,
10
+ subscribe
11
+ } from '../runtime';
12
+ import { addAppConfigs } from '../runtime/config';
13
+ import { addAppMessages } from '../runtime/i18n';
14
+ import messages from './i18n';
15
+ import createRouter from './router/createRouter';
16
+
17
+ subscribe(SITE_READY, async () => {
18
+ const queryClient = new QueryClient();
19
+ const router = createRouter();
20
+
21
+ addAppConfigs();
22
+ addAppMessages();
23
+
24
+ const root = createRoot(document.getElementById('root') as HTMLElement);
25
+ root.render(
26
+ <StrictMode>
27
+ <QueryClientProvider client={queryClient}>
28
+ <RouterProvider router={router} />,
29
+ </QueryClientProvider>
30
+ </StrictMode>
31
+ );
32
+ });
33
+
34
+ subscribe(SITE_INIT_ERROR, (error) => {
35
+ const root = createRoot(document.getElementById('root') as HTMLElement);
36
+ root.render(<div>{error.message}</div>);
37
+ });
38
+
39
+ initialize({
40
+ messages,
41
+ });
@@ -0,0 +1,15 @@
1
+ /// <reference types="@openedx/frontend-base" />
2
+
3
+ declare module 'site.config' {
4
+ export default SiteConfig;
5
+ }
6
+
7
+ declare module '*.svg' {
8
+ const content: string;
9
+ export default content;
10
+ }
11
+
12
+ declare module '*.jpg' {
13
+ const content: string;
14
+ export default content;
15
+ }
@@ -0,0 +1,2 @@
1
+ "use strict";(self.webpackChunktest_site=self.webpackChunktest_site||[]).push([[176],{2176:(e,r,s)=>{s.r(r),s.d(r,{default:()=>y});var t=s(7517),n=s(5029),i=s(8083),l=s(574),a=s(2800),c=s(5601),o=s(3440),d=s(8313),h=s(3273);const p=(0,s(7050).YK)({"test-site.message":{id:"test-site.message",defaultMessage:"This message proves that i18n is working."}});const g=e=>{var{alt:r}=e,s=function(e,r){var s={};for(var t in e)Object.prototype.hasOwnProperty.call(e,t)&&r.indexOf(t)<0&&(s[t]=e[t]);if(null!=e&&"function"==typeof Object.getOwnPropertySymbols){var n=0;for(t=Object.getOwnPropertySymbols(e);n<t.length;n++)r.indexOf(t[n])<0&&Object.prototype.propertyIsEnumerable.call(e,t[n])&&(s[t[n]]=e[t[n]])}return s}(e,["alt"]);return(0,t.jsx)("img",Object.assign({alt:r},s))};var x=s(2907),j=s.n(x),m=s(7141),f=s.n(m);const u=(0,d.forwardRef)(((e,r)=>{let{direction:s,gap:t,reversed:n,children:i,className:l}=e,a=function(e,r){var s={};for(var t in e)Object.prototype.hasOwnProperty.call(e,t)&&r.indexOf(t)<0&&(s[t]=e[t]);if(null!=e&&"function"==typeof Object.getOwnPropertySymbols){var n=0;for(t=Object.getOwnPropertySymbols(e);n<t.length;n++)r.indexOf(t[n])<0&&Object.prototype.propertyIsEnumerable.call(e,t[n])&&(s[t[n]]=e[t[n]])}return s}(e,["direction","gap","reversed","children","className"]);return d.createElement("div",Object.assign({ref:r,className:f()("horizontal"===s?"pgn__hstack":"pgn__vstack",t?`pgn__stack-gap--${t}`:"",n?"pgn__stack-reversed":"",l)},a),i)}));u.propTypes={children:j().node.isRequired,direction:j().oneOf(["horizontal","vertical"]),gap:j().number,reversed:j().bool,className:j().string},u.defaultProps={direction:"vertical",gap:0,className:void 0,reversed:!1};const b=u;var v=s(4152);const N=()=>{var e,r;return PARAGON_THEME?(0,t.jsxs)(t.Fragment,{children:[(0,t.jsx)("h2",{children:"Paragon"}),(0,t.jsxs)(b,{gap:4.5,children:[(0,t.jsxs)("div",{children:[(0,t.jsx)("h3",{children:"Component preview"}),(0,t.jsx)("div",{className:"px-3 py-2 bg-light-200",children:(0,t.jsx)(v.Ay,{children:"Hello world"})})]}),(0,t.jsxs)("div",{children:[(0,t.jsx)("h3",{children:"Exposed theme CSS files"}),(0,t.jsx)("p",{children:(0,t.jsxs)("em",{children:["Note: Depending on the versions of ",(0,t.jsx)("code",{children:"@openedx/paragon"})," and/or ",(0,t.jsx)("code",{children:"@edx/brand"})," installed, it is expected that no exposed theme CSS assets be listed here."]})}),(0,t.jsxs)("ul",{className:"mb-0",children:[PARAGON_THEME.paragon.themeUrls.core.fileName&&(0,t.jsx)("li",{children:(0,t.jsx)("a",{href:`/${PARAGON_THEME.paragon.themeUrls.core.fileName}`,target:"_blank",rel:"noopener noreferrer",children:PARAGON_THEME.paragon.themeUrls.core.fileName})}),(null===(e=PARAGON_THEME.paragon.themeUrls.variants.light)||void 0===e?void 0:e.fileName)&&(0,t.jsx)("li",{children:(0,t.jsx)("a",{href:`/${PARAGON_THEME.paragon.themeUrls.variants.light.fileName}`,target:"_blank",rel:"noopener noreferrer",children:PARAGON_THEME.paragon.themeUrls.variants.light.fileName})}),PARAGON_THEME.brand.themeUrls.core.fileName&&(0,t.jsx)("li",{children:(0,t.jsx)("a",{href:`/${PARAGON_THEME.brand.themeUrls.core.fileName}`,target:"_blank",rel:"noopener noreferrer",children:PARAGON_THEME.brand.themeUrls.core.fileName})}),(null===(r=PARAGON_THEME.brand.themeUrls.variants.light)||void 0===r?void 0:r.fileName)&&(0,t.jsx)("li",{children:(0,t.jsx)("a",{href:`/${PARAGON_THEME.brand.themeUrls.variants.light.fileName}`,target:"_blank",rel:"noopener noreferrer",children:PARAGON_THEME.brand.themeUrls.variants.light.fileName})})]})]}),(0,t.jsxs)("div",{children:[(0,t.jsxs)("h3",{children:["Contents of ",(0,t.jsx)("code",{children:"PARAGON_THEME"})," global variable"]}),(0,t.jsx)("pre",{children:JSON.stringify(PARAGON_THEME,null,2)})]})]})]}):(0,t.jsxs)("p",{children:["Missing ",(0,t.jsx)("code",{children:"PARAGON_THEME"})," global variable. Depending on configuration, this may be OK."]})},A=s.p+"74e025d3fe9a7b7f8503054e2563b353.jpg",O=s.p+"cb28cdb1468c915e27e5cec9af64f22f.svg";function E(e){return e?"✅":"❌"}function y(){const e=(0,n.zn)(),r=(0,n.QR)(),s=(0,i.A)();return(0,d.useEffect)((()=>{(0,l.fH)("The example page can log info, which means logging is configured correctly.")}),[]),(0,t.jsxs)(o.A,{children:[(0,t.jsxs)("h1",{children:[e.siteName," test page"]}),(0,t.jsx)("h2",{children:"Links"}),(0,t.jsxs)("p",{children:["Visit ",(0,t.jsx)(h.N_,{to:"/authenticated",children:"authenticated page"}),"."]}),(0,t.jsxs)("p",{children:["Visit ",(0,t.jsx)(h.N_,{to:"/error",children:"error page"}),"."]}),(0,t.jsx)("h2",{children:"Context Config Test"}),(0,t.jsxs)("p",{children:["Is context.config equal to getSiteConfig()? ",E(e===(0,a.Q2)())]}),(0,t.jsxs)("p",{children:["Is context.authenticatedUser equal to getAuthenticatedUser()? ",E(r===(0,c.vD)())]}),(0,t.jsx)("h2",{children:"SCSS parsing tests"}),(0,t.jsxs)("p",{children:[(0,t.jsx)("span",{className:"red-text",children:'"The Apples"'})," should be red (",(0,t.jsx)("code",{children:"color: red;"})," via ",(0,t.jsx)("code",{children:".red-text"})," CSS class in SCSS stylesheet)"]}),(0,t.jsx)("h2",{children:"TSX parsing tests"}),(0,t.jsx)(g,{src:O,alt:"apple.svg displayed in Image.tsx",style:{width:"10rem"}}),(0,t.jsx)("h2",{children:"SVG import test"}),(0,t.jsx)("img",{src:O,alt:"apple.svg displayed in <img> tag",style:{width:"10rem"}}),(0,t.jsx)("h2",{children:"JPG import test"}),(0,t.jsx)("p",{children:(0,t.jsx)("img",{src:A,alt:"apple.jpg displayed in <img> tag",style:{width:"10rem"}})}),(0,t.jsx)("p",{children:"Photo by Louis Hansel @shotsoflouis on Unsplash"}),(0,t.jsx)("h2",{children:"i18n formatMessage test"}),(0,t.jsx)("p",{children:s.formatMessage(p["test-site.message"])}),(0,t.jsx)("h2",{children:"Authenticated User Test"}),null!==r?(0,t.jsxs)("div",{children:[(0,t.jsxs)("p",{children:["Authenticated Username: ",(0,t.jsx)("strong",{children:r.username})]}),(0,t.jsxs)("p",{children:["Authenticated user's name:",(0,t.jsx)("strong",{children:r.username}),"(Only available if user account has been fetched)"]})]}):(0,t.jsxs)("p",{children:["Unauthenticated ",E(null===r)]}),(0,t.jsx)("h2",{children:"Right-to-left language handling tests"}),(0,t.jsx)("p",{className:"text-align-right",children:"I'm aligned right, but left in RTL."}),(0,t.jsx)(N,{})]})}}}]);
2
+ //# sourceMappingURL=176.436443549ebb858db483.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"176.436443549ebb858db483.js","mappings":"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","sources":["webpack://test-site/./src/messages.js","webpack://test-site/./src/example-page/Image.tsx","webpack://test-site/./node_modules/@openedx/paragon/src/Stack/index.jsx","webpack://test-site/./src/example-page/ParagonPreview.jsx","webpack://test-site/./src/example-page/apple.jpg","webpack://test-site/./src/example-page/apple.svg","webpack://test-site/./src/example-page/ExamplePage.tsx"],"sourcesContent":["import { defineMessages } from '@openedx/frontend-base';\n\nconst messages = defineMessages({\n 'test-site.message': {\n id: 'test-site.message',\n defaultMessage: 'This message proves that i18n is working.',\n description: 'A message that proves that internationalization is working.',\n },\n});\n\nexport default messages;\n","import { CSSProperties } from 'react';\n\ninterface ImageProps {\n src: string,\n alt?: string,\n style?: CSSProperties,\n}\n\nconst Image = ({ alt, ...rest }: ImageProps) => <img alt={alt} {...rest} />;\n\nexport default Image;\n","import React, { forwardRef } from 'react';\nimport PropTypes from 'prop-types';\nimport classNames from 'classnames';\n\nconst DIRECTION_VARIANTS = [\n 'horizontal',\n 'vertical',\n];\n\nconst Stack = forwardRef(({\n direction,\n gap,\n reversed,\n children,\n className,\n ...rest\n}, ref) => (\n <div\n ref={ref}\n className={classNames(\n direction === 'horizontal' ? 'pgn__hstack' : 'pgn__vstack',\n gap ? `pgn__stack-gap--${gap}` : '',\n reversed ? 'pgn__stack-reversed' : '',\n className,\n )}\n {...rest}\n >\n {children}\n </div>\n));\n\nStack.propTypes = {\n /** Specifies the content of the `Stack`. */\n children: PropTypes.node.isRequired,\n /** Specifies direction of the children blocks (column/row). */\n direction: PropTypes.oneOf(DIRECTION_VARIANTS),\n /**\n * Specifies inner space between children blocks.\n *\n * Valid values are based on `the spacing classes`:\n * `0, 0.5, ... 6`.\n */\n gap: PropTypes.number,\n /** Specifies the order of the children. */\n reversed: PropTypes.bool,\n /** Specifies an additional `className` to add to the base element. */\n className: PropTypes.string,\n};\n\nStack.defaultProps = {\n direction: 'vertical',\n gap: 0,\n className: undefined,\n reversed: false,\n};\n\nexport default Stack;\n","import { Button, Stack } from '@openedx/paragon';\n\nconst ParagonPreview = () => {\n if (!PARAGON_THEME) {\n return <p>Missing <code>PARAGON_THEME</code> global variable. Depending on configuration, this may be OK.</p>;\n }\n return (\n <>\n <h2>Paragon</h2>\n\n <Stack gap={4.5}>\n <div>\n <h3>Component preview</h3>\n <div className=\"px-3 py-2 bg-light-200\">\n <Button>Hello world</Button>\n </div>\n </div>\n <div>\n <h3>Exposed theme CSS files</h3>\n <p>\n <em>\n Note: Depending on the versions of <code>@openedx/paragon</code> and/or <code>@edx/brand</code> installed,\n it is expected that no exposed theme CSS assets be listed here.\n </em>\n </p>\n <ul className=\"mb-0\">\n {PARAGON_THEME.paragon.themeUrls.core.fileName && (\n <li>\n <a href={`/${PARAGON_THEME.paragon.themeUrls.core.fileName}`} target=\"_blank\" rel=\"noopener noreferrer\">\n {PARAGON_THEME.paragon.themeUrls.core.fileName}\n </a>\n </li>\n )}\n {PARAGON_THEME.paragon.themeUrls.variants.light?.fileName && (\n <li>\n <a href={`/${PARAGON_THEME.paragon.themeUrls.variants.light.fileName}`} target=\"_blank\" rel=\"noopener noreferrer\">\n {PARAGON_THEME.paragon.themeUrls.variants.light.fileName}\n </a>\n </li>\n )}\n {PARAGON_THEME.brand.themeUrls.core.fileName && (\n <li>\n <a href={`/${PARAGON_THEME.brand.themeUrls.core.fileName}`} target=\"_blank\" rel=\"noopener noreferrer\">\n {PARAGON_THEME.brand.themeUrls.core.fileName}\n </a>\n </li>\n )}\n {PARAGON_THEME.brand.themeUrls.variants.light?.fileName && (\n <li>\n <a href={`/${PARAGON_THEME.brand.themeUrls.variants.light.fileName}`} target=\"_blank\" rel=\"noopener noreferrer\">\n {PARAGON_THEME.brand.themeUrls.variants.light.fileName}\n </a>\n </li>\n )}\n </ul>\n </div>\n <div>\n <h3>Contents of <code>PARAGON_THEME</code> global variable</h3>\n <pre>{JSON.stringify(PARAGON_THEME, null, 2)}</pre>\n </div>\n </Stack>\n </>\n );\n};\n\nexport default ParagonPreview;\n","export default __webpack_public_path__ + \"74e025d3fe9a7b7f8503054e2563b353.jpg\";","export default __webpack_public_path__ + \"cb28cdb1468c915e27e5cec9af64f22f.svg\";","import {\n getAuthenticatedUser,\n getSiteConfig,\n logInfo,\n useAuthenticatedUser,\n useSiteConfig,\n useIntl\n} from '@openedx/frontend-base';\nimport { Container } from '@openedx/paragon';\nimport { useEffect } from 'react';\nimport { Link } from 'react-router-dom';\nimport messages from '../messages';\nimport Image from './Image';\nimport ParagonPreview from './ParagonPreview';\nimport appleImg from './apple.jpg';\nimport appleUrl from './apple.svg';\n\nfunction printTestResult(value) {\n return value ? '✅' : '❌';\n}\n\nexport default function ExamplePage() {\n const config = useSiteConfig();\n const authenticatedUser = useAuthenticatedUser();\n\n const intl = useIntl();\n\n useEffect(() => {\n logInfo('The example page can log info, which means logging is configured correctly.');\n }, []);\n\n return (\n <Container>\n <h1>{config.siteName} test page</h1>\n\n <h2>Links</h2>\n <p>Visit <Link to=\"/authenticated\">authenticated page</Link>.</p>\n <p>Visit <Link to=\"/error\">error page</Link>.</p>\n\n <h2>Context Config Test</h2>\n <p>Is context.config equal to getSiteConfig()? {printTestResult(config === getSiteConfig())}</p>\n <p>Is context.authenticatedUser equal to getAuthenticatedUser()? {printTestResult(authenticatedUser === getAuthenticatedUser())}</p>\n\n <h2>SCSS parsing tests</h2>\n <p><span className=\"red-text\">&quot;The Apples&quot;</span> should be red (<code>color: red;</code> via <code>.red-text</code> CSS class in SCSS stylesheet)</p>\n\n <h2>TSX parsing tests</h2>\n <Image src={appleUrl} alt=\"apple.svg displayed in Image.tsx\" style={{ width: '10rem' }} />\n\n <h2>SVG import test</h2>\n <img src={appleUrl} alt=\"apple.svg displayed in <img> tag\" style={{ width: '10rem' }} />\n\n <h2>JPG import test</h2>\n <p><img src={appleImg} alt=\"apple.jpg displayed in <img> tag\" style={{ width: '10rem' }} /></p>\n <p>Photo by Louis Hansel @shotsoflouis on Unsplash</p>\n\n <h2>i18n formatMessage test</h2>\n <p>{intl.formatMessage(messages['test-site.message'])}</p>\n\n <h2>Authenticated User Test</h2>\n {authenticatedUser !== null ? (\n <div>\n <p>Authenticated Username: <strong>{authenticatedUser.username}</strong></p>\n <p>\n Authenticated user&apos;s name:\n <strong>{authenticatedUser.username}</strong>\n (Only available if user account has been fetched)\n </p>\n </div>\n ) : (\n <p>Unauthenticated {printTestResult(authenticatedUser === null)}</p>\n )}\n\n <h2>Right-to-left language handling tests</h2>\n <p className=\"text-align-right\">I&apos;m aligned right, but left in RTL.</p>\n <ParagonPreview />\n </Container>\n );\n}\n"],"names":["alt","rest","Stack","forwardRef","_ref","ref","direction","gap","reversed","children","className","React","classNames","propTypes","PropTypes","isRequired","defaultProps","undefined","PARAGON_THEME","Button","paragon","themeUrls","core","fileName","href","target","rel","variants","light","brand","JSON","stringify","printTestResult","value","ExamplePage","config","authenticatedUser","intl","useIntl","useEffect","Container","siteName","to","src","style","width","apple","formatMessage","username"],"sourceRoot":""}
@@ -0,0 +1,2 @@
1
+ "use strict";(self.webpackChunktest_site=self.webpackChunktest_site||[]).push([[362],{5362:(e,s,t)=>{t.r(s),t.d(s,{default:()=>u});var i=t(7517),n=t(8313),r=t(8083),a=t(3879),c=t(2880),h=t(7409);const o=(0,t(7050).YK)({loading:{id:"loading.message.text",defaultMessage:"Loading"},unexpectedError:{id:"unexpected.error.message.text",defaultMessage:"Oops! An error occurred. Please refresh the screen to try again."}}),d=()=>{const{formatMessage:e}=(0,r.A)();return(0,i.jsx)("div",{children:(0,i.jsx)("h2",{children:e(o.unexpectedError)})})};function l({children:e,className:s,style:t={},ready:r=!0,errorFallbackComponent:o}){const[l,u]=(0,n.useState)({width:0,height:0}),g=(0,n.useMemo)((()=>Object.assign(Object.assign({},l),t)),[l,t]),f=null!=o?o:d;return(0,h.in)(c.GV,(({payload:e})=>{u({width:e.width,height:e.height})})),(0,n.useEffect)((()=>((0,h.dh)(),()=>{(0,h.wt)()})),[]),(0,n.useEffect)((()=>{r&&(0,h.uj)()}),[r]),(0,i.jsx)("div",{className:s,style:g,children:(0,i.jsx)(a.A,{fallbackComponent:(0,i.jsx)(f,{}),children:e})})}function u(){return(0,i.jsx)(l,{children:(0,i.jsxs)("section",{className:"bg-light p-3 h-100",children:[(0,i.jsx)("h4",{children:"Inserted iFrame Widget"}),(0,i.jsx)("p",{children:"This is a component that lives in the test-site but is loaded into the page via an iframe. This emulates a real-world scenario. It is NOT testing for cross-origin security issues though, since it's on the same host name."})]})})}}}]);
2
+ //# sourceMappingURL=362.536eff787d2380fe246c.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"362.536eff787d2380fe246c.js","mappings":"mMAEA,MAaA,GAbiB,E,QAAA,IAAe,CAC9BA,QAAS,CAAF,oDAKPC,gBAAiB,CAAF,wHCSXC,EAAuB,KAC3B,MAAM,cAAEC,IAAkB,EAAAC,EAAA,KAC1B,OACE,0BACE,wBACGD,EAAc,EAASF,sBAcjB,SAASI,GAAqB,SAC3CC,EAAQ,UAAEC,EAAS,MAAEC,EAAQ,CAAC,EAAC,MAAEC,GAAQ,EAAI,uBAAEC,IAE/C,MAAOC,EAAYC,IAAiB,IAAAC,UAAS,CAC3CC,MAAO,EACPC,OAAQ,IAGJC,GAAa,IAAAC,UAAQ,IAAO,OAAD,wBAC5BN,GACAH,IACD,CAACG,EAAYH,IAIXU,EAAgBR,QAAAA,EAA0BR,EAyBhD,OAvBA,QAAa,MAAe,EAAGiB,cAC7BP,EAAc,CACZE,MAAOK,EAAQL,MACfC,OAAQI,EAAQJ,aAIpB,IAAAK,YAAU,MACR,UAEO,MACL,aAED,KAEH,IAAAA,YAAU,KAGJX,IACF,YAED,CAACA,KAGF,gBAAKF,UAAWA,EAAWC,MAAOQ,EAAU,UAC1C,SAACK,EAAA,EAAa,CAACC,mBAAmB,SAACJ,EAAa,IAAG,SAChDZ,KAIT,CCjFe,SAASiB,IACtB,OACE,SAAClB,EAAoB,WACnB,qBAASE,UAAU,qBAAoB,WACrC,oDACA,8PAMR,C","sources":["webpack://test-site/./node_modules/@openedx/frontend-base/runtime/slots/widget/iframe/IFrameContentWrapper.messages.tsx","webpack://test-site/./node_modules/@openedx/frontend-base/runtime/slots/widget/iframe/IFrameContentWrapper.tsx","webpack://test-site/./src/iframe-widget/IframeWidget.tsx"],"sourcesContent":["import { defineMessages } from '../../../i18n';\n\nconst messages = defineMessages({\n loading: {\n id: 'loading.message.text',\n defaultMessage: 'Loading',\n description: 'the feature is currently loading',\n },\n unexpectedError: {\n id: 'unexpected.error.message.text',\n defaultMessage: ' Oops! An error occurred. Please refresh the screen to try again.',\n description: 'error message when an unexpected error occurs',\n },\n});\n\nexport default messages;\n","import {\n FunctionComponent,\n ReactNode,\n useEffect, useMemo, useState,\n} from 'react';\n\nimport { useIntl } from '../../../i18n';\nimport { ErrorBoundary } from '../../../react';\nimport { IFRAME_RESIZE } from './constants';\nimport {\n dispatchMountedEvent,\n dispatchReadyEvent,\n dispatchUnmountedEvent,\n useHostEvent\n} from './hooks';\nimport messages from './IFrameContentWrapper.messages';\n\nconst ErrorFallbackDefault = () => {\n const { formatMessage } = useIntl();\n return (\n <div>\n <h2>\n {formatMessage(messages.unexpectedError)}\n </h2>\n </div>\n );\n};\n\ninterface IFrameContentWrapperProps {\n children: ReactNode,\n className?: string,\n style?: Record<string, string>,\n ready?: boolean,\n errorFallbackComponent?: FunctionComponent,\n}\n\nexport default function IFrameContentWrapper({\n children, className, style = {}, ready = true, errorFallbackComponent,\n}: IFrameContentWrapperProps) {\n const [dimensions, setDimensions] = useState({\n width: 0,\n height: 0,\n });\n\n const finalStyle = useMemo(() => ({\n ...dimensions,\n ...style,\n }), [dimensions, style]);\n\n // Need to confirm: When an error is caught here, the logging will be sent to the child MFE's logging service\n\n const ErrorFallback = errorFallbackComponent ?? ErrorFallbackDefault;\n\n useHostEvent(IFRAME_RESIZE, ({ payload }) => {\n setDimensions({\n width: payload.width,\n height: payload.height,\n });\n });\n\n useEffect(() => {\n dispatchMountedEvent();\n\n return () => {\n dispatchUnmountedEvent();\n };\n }, []);\n\n useEffect(() => {\n // Ready defaults to true, but can be used to defer rendering the Plugin until certain processes\n // have occurred or conditions have been met\n if (ready) {\n dispatchReadyEvent();\n }\n }, [ready]);\n\n return (\n <div className={className} style={finalStyle}>\n <ErrorBoundary fallbackComponent={<ErrorFallback />}>\n {children}\n </ErrorBoundary>\n </div>\n );\n};\n","import { IFrameContentWrapper } from '@openedx/frontend-base';\n\nexport default function IframeWidget() {\n return (\n <IFrameContentWrapper>\n <section className=\"bg-light p-3 h-100\">\n <h4>Inserted iFrame Widget</h4>\n <p>\n This is a component that lives in the test-site but is loaded into the page via an iframe. This emulates a real-world scenario. It is NOT testing for cross-origin security issues though, since it&apos;s on the same host name.\n </p>\n </section>\n </IFrameContentWrapper>\n );\n}\n"],"names":["loading","unexpectedError","ErrorFallbackDefault","formatMessage","useIntl","IFrameContentWrapper","children","className","style","ready","errorFallbackComponent","dimensions","setDimensions","useState","width","height","finalStyle","useMemo","ErrorFallback","payload","useEffect","ErrorBoundary","fallbackComponent","IframeWidget"],"sourceRoot":""}
@@ -0,0 +1,2 @@
1
+ "use strict";(self.webpackChunktest_site=self.webpackChunktest_site||[]).push([[653],{8653:(e,s,t)=>{t.r(s),t.d(s,{default:()=>h});var a=t(7517),i=t(3273),n=t(5029),c=t(6024);function h(){const e=(0,n.QR)(),s=(0,n.zn)();return(0,a.jsxs)("main",{className:"p-3",children:[(0,a.jsxs)("h1",{children:[s.siteName," authenticated page."]}),(0,a.jsx)(c.A,{id:"authenticated.page.content",defaultMessage:"This is a localized message. Try it in French."}),(0,a.jsx)("p",{children:null===e?"You are not authenticated.":`Hi there, ${e.username}.`}),(0,a.jsxs)("p",{children:["Visit ",(0,a.jsx)(i.N_,{to:"/",children:"public page"}),"."]})]})}}}]);
2
+ //# sourceMappingURL=653.486966b108d224551296.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"653.486966b108d224551296.js","mappings":"+KAKe,SAASA,IACtB,MAAMC,GAAoB,UACpBC,GAAS,UAEf,OACE,kBAAMC,UAAU,MAAK,WACnB,0BAAKD,EAAOE,SAAQ,2BACpB,SAAC,IAAgB,oGACjB,uBAA0B,OAAtBH,EAA6B,6BAA+B,aAAaA,EAAkBI,eAC/F,mCAAS,SAAC,KAAI,CAACC,GAAG,IAAG,yBAAmB,SAG9C,C","sources":["webpack://test-site/./src/authenticated-page/AuthenticatedPage.tsx"],"sourcesContent":["import { Link } from 'react-router-dom';\n\nimport { useAuthenticatedUser, useSiteConfig } from '@openedx/frontend-base';\nimport { FormattedMessage } from 'react-intl';\n\nexport default function AuthenticatedPage() {\n const authenticatedUser = useAuthenticatedUser();\n const config = useSiteConfig();\n\n return (\n <main className=\"p-3\">\n <h1>{config.siteName} authenticated page.</h1>\n <FormattedMessage id=\"authenticated.page.content\" defaultMessage=\"This is a localized message. Try it in French.\" description=\"This is a test message to prove localization works.\" />\n <p>{authenticatedUser === null ? 'You are not authenticated.' : `Hi there, ${authenticatedUser.username}.`}</p>\n <p>Visit <Link to=\"/\">public page</Link>.</p>\n </main>\n );\n}\n"],"names":["AuthenticatedPage","authenticatedUser","config","className","siteName","username","to"],"sourceRoot":""}