acinguiux-preact-components 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (313) hide show
  1. package/package.json +56 -0
  2. package/src/content/themes/theme-acinguiux-amg/theme-acinguiux-amg.css +23 -0
  3. package/src/content/themes/theme-acinguiux-cafe/theme-acinguiux-cafe.css +47 -0
  4. package/src/content/themes/theme-acinguiux-energy/theme-acinguiux-energy.css +45 -0
  5. package/src/content/themes/theme-acinguiux-livewire/theme-acinguiux-livewire.css +22 -0
  6. package/src/content/themes/theme-acinguiux-livewire-italy/theme-acinguiux-livewire-italy.css +22 -0
  7. package/src/content/themes/theme-acinguiux-recharge/theme-acinguiux-recharge.css +49 -0
  8. package/src/content/themes/theme-allon/theme-allon.css +25 -0
  9. package/src/content/themes/theme-atlas/theme-atlas.css +31 -0
  10. package/src/content/themes/theme-aurvana/resources/favicon/apple-touch-icon.png +0 -0
  11. package/src/content/themes/theme-aurvana/resources/favicon/favico.ico +0 -0
  12. package/src/content/themes/theme-aurvana/resources/favicon/favicon-96x96.png +0 -0
  13. package/src/content/themes/theme-aurvana/resources/favicon/favicon.ico +0 -0
  14. package/src/content/themes/theme-aurvana/resources/favicon/favicon.png +0 -0
  15. package/src/content/themes/theme-aurvana/resources/favicon/favicon.svg +13 -0
  16. package/src/content/themes/theme-aurvana/resources/favicon/google-touch-icon.png +0 -0
  17. package/src/content/themes/theme-aurvana/resources/favicon/manifest.json +14 -0
  18. package/src/content/themes/theme-aurvana/resources/favicon/site.webmanifest +21 -0
  19. package/src/content/themes/theme-aurvana/resources/favicon/web-app-manifest-192x192.png +0 -0
  20. package/src/content/themes/theme-aurvana/resources/favicon/web-app-manifest-512x512.png +0 -0
  21. package/src/content/themes/theme-aurvana/theme-aurvana.css +49 -0
  22. package/src/content/themes/theme-base/theme-base.css +49 -0
  23. package/src/content/themes/theme-base2/resources/favicon/android-chrome-192x192.png +0 -0
  24. package/src/content/themes/theme-base2/resources/favicon/android-chrome-512x512.png +0 -0
  25. package/src/content/themes/theme-base2/resources/favicon/apple-touch-icon.png +0 -0
  26. package/src/content/themes/theme-base2/resources/favicon/favico.ico +0 -0
  27. package/src/content/themes/theme-base2/resources/favicon/favicon-16x16.png +0 -0
  28. package/src/content/themes/theme-base2/resources/favicon/favicon-32x32.png +0 -0
  29. package/src/content/themes/theme-base2/resources/favicon/favicon-96x96.png +0 -0
  30. package/src/content/themes/theme-base2/resources/favicon/favicon.ico +0 -0
  31. package/src/content/themes/theme-base2/resources/favicon/favicon.png +0 -0
  32. package/src/content/themes/theme-base2/resources/favicon/favicon.svg +9 -0
  33. package/src/content/themes/theme-base2/resources/favicon/google-touch-icon.png +0 -0
  34. package/src/content/themes/theme-base2/resources/favicon/manifest.json +14 -0
  35. package/src/content/themes/theme-base2/resources/favicon/site.webmanifest +1 -0
  36. package/src/content/themes/theme-base2/resources/favicon/web-app-manifest-192x192.png +0 -0
  37. package/src/content/themes/theme-base2/resources/favicon/web-app-manifest-512x512.png +0 -0
  38. package/src/content/themes/theme-base2/resources/fonts/acinguiux-typeface-la-heavy-221208.woff2 +0 -0
  39. package/src/content/themes/theme-base2/theme-base2.css +47 -0
  40. package/src/content/themes/theme-eco-marathon/theme-eco-marathon.css +22 -0
  41. package/src/content/themes/theme-energy-transition-campus-amsterdam/theme-energy-transition-campus-amsterdam.css +26 -0
  42. package/src/content/themes/theme-evpass/theme-evpass.css +46 -0
  43. package/src/content/themes/theme-nam-2025/resources/favicon/apple-touch-icon.png +0 -0
  44. package/src/content/themes/theme-nam-2025/resources/favicon/favico.ico +0 -0
  45. package/src/content/themes/theme-nam-2025/resources/favicon/favicon-96x96.png +0 -0
  46. package/src/content/themes/theme-nam-2025/resources/favicon/favicon.ico +0 -0
  47. package/src/content/themes/theme-nam-2025/resources/favicon/favicon.png +0 -0
  48. package/src/content/themes/theme-nam-2025/resources/favicon/favicon.svg +9 -0
  49. package/src/content/themes/theme-nam-2025/resources/favicon/google-touch-icon.png +0 -0
  50. package/src/content/themes/theme-nam-2025/resources/favicon/manifest.json +14 -0
  51. package/src/content/themes/theme-nam-2025/resources/favicon/site.webmanifest +21 -0
  52. package/src/content/themes/theme-nam-2025/resources/favicon/web-app-manifest-192x192.png +0 -0
  53. package/src/content/themes/theme-nam-2025/resources/favicon/web-app-manifest-512x512.png +0 -0
  54. package/src/content/themes/theme-nam-2025/theme-nam-2025.css +47 -0
  55. package/src/content/themes/theme-pennzoil/theme-pennzoil.css +36 -0
  56. package/src/content/themes/theme-quaker-state/theme-quaker-state.css +63 -0
  57. package/src/content/themes/theme-tafawoq/theme-tafawoq.css +26 -0
  58. package/src/content/themes/theme-vegetable/resources/favicon/apple-touch-icon.png +0 -0
  59. package/src/content/themes/theme-vegetable/resources/favicon/favico.ico +0 -0
  60. package/src/content/themes/theme-vegetable/resources/favicon/favicon-96x96.png +0 -0
  61. package/src/content/themes/theme-vegetable/resources/favicon/favicon.ico +0 -0
  62. package/src/content/themes/theme-vegetable/resources/favicon/favicon.png +0 -0
  63. package/src/content/themes/theme-vegetable/resources/favicon/favicon.svg +13 -0
  64. package/src/content/themes/theme-vegetable/resources/favicon/google-touch-icon.png +0 -0
  65. package/src/content/themes/theme-vegetable/resources/favicon/manifest.json +14 -0
  66. package/src/content/themes/theme-vegetable/resources/favicon/site.webmanifest +21 -0
  67. package/src/content/themes/theme-vegetable/resources/favicon/web-app-manifest-192x192.png +0 -0
  68. package/src/content/themes/theme-vegetable/resources/favicon/web-app-manifest-512x512.png +0 -0
  69. package/src/content/themes/theme-vegetable/theme-vegetable.css +49 -0
  70. package/src/content/themes/theme-zeolyst/resources/fonts/type-ar-medium.woff2 +0 -0
  71. package/src/content/themes/theme-zeolyst/theme-zeolyst.css +29 -0
  72. package/src/main/atoms/audio.js +16 -0
  73. package/src/main/atoms/box.js +5 -0
  74. package/src/main/atoms/button.js +40 -0
  75. package/src/main/atoms/card.js +22 -0
  76. package/src/main/atoms/form.js +30 -0
  77. package/src/main/atoms/heading.js +17 -0
  78. package/src/main/atoms/icon.js +24 -0
  79. package/src/main/atoms/img.js +131 -0
  80. package/src/main/atoms/input.js +55 -0
  81. package/src/main/atoms/link-text.js +21 -0
  82. package/src/main/atoms/link.js +60 -0
  83. package/src/main/atoms/list.js +12 -0
  84. package/src/main/atoms/logo.js +9 -0
  85. package/src/main/atoms/menu.js +10 -0
  86. package/src/main/atoms/message.js +5 -0
  87. package/src/main/atoms/nav-link.js +49 -0
  88. package/src/main/atoms/popup.js +47 -0
  89. package/src/main/atoms/rich-text.js +128 -0
  90. package/src/main/atoms/scroller.js +224 -0
  91. package/src/main/atoms/svg.js +65 -0
  92. package/src/main/atoms/table.js +32 -0
  93. package/src/main/atoms/textarea.js +10 -0
  94. package/src/main/atoms/time.js +12 -0
  95. package/src/main/atoms/video.js +100 -0
  96. package/src/main/export-main.js +12 -0
  97. package/src/main/export-matter.js +86 -0
  98. package/src/main/export-preact-hooks.js +1 -0
  99. package/src/main/export-preact.js +1 -0
  100. package/src/main/index.js +13 -0
  101. package/src/main/molecules/asset.js +23 -0
  102. package/src/main/molecules/glossary.js +44 -0
  103. package/src/main/molecules/links.js +23 -0
  104. package/src/main/molecules/promo-text.js +27 -0
  105. package/src/main/molecules/tags.js +15 -0
  106. package/src/main/molecules/tree.js +51 -0
  107. package/src/main/organisms/accordion-item.js +106 -0
  108. package/src/main/organisms/author.js +29 -0
  109. package/src/main/organisms/breadcrumb.js +69 -0
  110. package/src/main/organisms/call-to-action.js +24 -0
  111. package/src/main/organisms/carousel.js +178 -0
  112. package/src/main/organisms/cart-item.js +156 -0
  113. package/src/main/organisms/cart.js +162 -0
  114. package/src/main/organisms/contact-form.js +141 -0
  115. package/src/main/organisms/container/ab-test.js +47 -0
  116. package/src/main/organisms/container/default.js +6 -0
  117. package/src/main/organisms/container/filtered-section.js +293 -0
  118. package/src/main/organisms/container/footer.js +12 -0
  119. package/src/main/organisms/container/grid.js +44 -0
  120. package/src/main/organisms/container/header.js +13 -0
  121. package/src/main/organisms/container/list.js +7 -0
  122. package/src/main/organisms/container/main.js +6 -0
  123. package/src/main/organisms/container/raw.js +7 -0
  124. package/src/main/organisms/container/section.js +28 -0
  125. package/src/main/organisms/container.js +29 -0
  126. package/src/main/organisms/content-owner.js +15 -0
  127. package/src/main/organisms/date-entry.js +56 -0
  128. package/src/main/organisms/external-search.js +73 -0
  129. package/src/main/organisms/filtered-item.js +163 -0
  130. package/src/main/organisms/footer-item.js +17 -0
  131. package/src/main/organisms/image-gallery.js +164 -0
  132. package/src/main/organisms/last-modified.js +20 -0
  133. package/src/main/organisms/legal-footer.js +16 -0
  134. package/src/main/organisms/list-item.js +48 -0
  135. package/src/main/organisms/metadata.js +11 -0
  136. package/src/main/organisms/navigation.js +232 -0
  137. package/src/main/organisms/notification.js +87 -0
  138. package/src/main/organisms/order-tracker.js +203 -0
  139. package/src/main/organisms/page-header-banner.js +26 -0
  140. package/src/main/organisms/page-header.js +33 -0
  141. package/src/main/organisms/page-tags.js +14 -0
  142. package/src/main/organisms/page.js +260 -0
  143. package/src/main/organisms/press-release.js +24 -0
  144. package/src/main/organisms/product-admin.js +204 -0
  145. package/src/main/organisms/promo-banner.js +28 -0
  146. package/src/main/organisms/promo-bottom.js +23 -0
  147. package/src/main/organisms/promo-button.js +8 -0
  148. package/src/main/organisms/promo-card-cover.js +35 -0
  149. package/src/main/organisms/promo-card.js +33 -0
  150. package/src/main/organisms/promo-full.js +20 -0
  151. package/src/main/organisms/promo-image.js +22 -0
  152. package/src/main/organisms/promo-lure.js +22 -0
  153. package/src/main/organisms/promo-product-card.js +187 -0
  154. package/src/main/organisms/promo-product-full.js +293 -0
  155. package/src/main/organisms/promo-simple.js +23 -0
  156. package/src/main/organisms/quote.js +21 -0
  157. package/src/main/organisms/search-form.js +42 -0
  158. package/src/main/organisms/search-nav.js +66 -0
  159. package/src/main/organisms/search-result.js +53 -0
  160. package/src/main/organisms/slider.js +26 -0
  161. package/src/main/organisms/standalone-asset.js +22 -0
  162. package/src/main/organisms/tabs.js +277 -0
  163. package/src/main/organisms/topbar.js +83 -0
  164. package/src/main/organisms/web-component.js +53 -0
  165. package/src/main/routing/annotation.js +9 -0
  166. package/src/main/routing/component.js +138 -0
  167. package/src/main/routing/empty.js +5 -0
  168. package/src/main/routing/error-handler.js +64 -0
  169. package/src/main/routing/placeholder-image.svg +5 -0
  170. package/src/main/routing/router.js +219 -0
  171. package/src/main/shared/analytics.js +677 -0
  172. package/src/main/shared/bubble-event.js +11 -0
  173. package/src/main/shared/custom-element.js +21 -0
  174. package/src/main/shared/deep-selector.js +28 -0
  175. package/src/main/shared/disable-transparency.js +10 -0
  176. package/src/main/shared/format-time.js +8 -0
  177. package/src/main/shared/get-id.js +5 -0
  178. package/src/main/shared/get-meta.js +3 -0
  179. package/src/main/shared/get-size-class.js +3 -0
  180. package/src/main/shared/get-size.js +11 -0
  181. package/src/main/shared/h.js +88 -0
  182. package/src/main/shared/hash-jump.js +33 -0
  183. package/src/main/shared/icons/arrow-back.svg +1 -0
  184. package/src/main/shared/icons/arrow-down.svg +1 -0
  185. package/src/main/shared/icons/arrow-next.svg +1 -0
  186. package/src/main/shared/icons/arrow-tail-right.svg +1 -0
  187. package/src/main/shared/icons/arrow-tail-up.svg +1 -0
  188. package/src/main/shared/icons/arrow-up.svg +1 -0
  189. package/src/main/shared/icons/asset-download.svg +1 -0
  190. package/src/main/shared/icons/logo.svg +5 -0
  191. package/src/main/shared/icons/low-carbon-placeholder.svg +9 -0
  192. package/src/main/shared/icons/media-pause.svg +1 -0
  193. package/src/main/shared/icons/media-play.svg +1 -0
  194. package/src/main/shared/icons/navigation-burger.svg +1 -0
  195. package/src/main/shared/icons/navigation-close.svg +1 -0
  196. package/src/main/shared/icons/navigation-link.svg +1 -0
  197. package/src/main/shared/icons/navigation-refresh.svg +1 -0
  198. package/src/main/shared/icons/navigation-search.svg +1 -0
  199. package/src/main/shared/icons/navigation-share.svg +1 -0
  200. package/src/main/shared/icons/toggle-newwindow.svg +1 -0
  201. package/src/main/shared/icons.js +18 -0
  202. package/src/main/shared/id-from-string.js +5 -0
  203. package/src/main/shared/mark-selection.js +19 -0
  204. package/src/main/shared/register.js +26 -0
  205. package/src/main/shared/renderer.js +43 -0
  206. package/src/main/shared/simple-consent-api.js +70 -0
  207. package/src/main/shared/split-links.js +11 -0
  208. package/src/main/shared/t.js +60 -0
  209. package/src/main/shared/twind.js +837 -0
  210. package/src/main/shared/update-head.js +34 -0
  211. package/src/main/shared/update-scrollbar-width.js +30 -0
  212. package/src/main/shared/use-link.js +151 -0
  213. package/src/main/shared/use-persistent-state.js +42 -0
  214. package/src/main/shared/wait-for-dom-ready.js +6 -0
  215. package/src/main/shared/wcm-mode.js +4 -0
  216. package/src/wcs/components/acinguiux-preact-doc/acinguiux-preact-doc.js +207 -0
  217. package/src/wcs/components/admin-dashboard/admin-dashboard.js +487 -0
  218. package/src/wcs/components/admin-login/admin-login.js +91 -0
  219. package/src/wcs/components/bazaar-voice/bazaar-voice.js +56 -0
  220. package/src/wcs/components/chatbot-koreai/chatbot-koreai.js +176 -0
  221. package/src/wcs/components/chatbot-koreai/koreai-transport.js +217 -0
  222. package/src/wcs/components/chatbot-ms/chatbot-ms.js +210 -0
  223. package/src/wcs/components/chatbot-test/chatbot-test.js +44 -0
  224. package/src/wcs/components/comparison-chart/comparison-chart.js +111 -0
  225. package/src/wcs/components/consent-banner/consent-banner.js +248 -0
  226. package/src/wcs/components/consent-banner/icons/ccpa.svg +6 -0
  227. package/src/wcs/components/consent-banner/icons/info.svg +1 -0
  228. package/src/wcs/components/consent-banner/provider-onetrust.js +131 -0
  229. package/src/wcs/components/decision-tree/arrow-back.svg +3 -0
  230. package/src/wcs/components/decision-tree/badges.js +37 -0
  231. package/src/wcs/components/decision-tree/decision-tree.js +162 -0
  232. package/src/wcs/components/dynamic-contact-details/dynamic-contact-details.js +111 -0
  233. package/src/wcs/components/example-accordion/example-accordion.js +10 -0
  234. package/src/wcs/components/example-asset/example-asset.js +12 -0
  235. package/src/wcs/components/example-form/example-form.js +59 -0
  236. package/src/wcs/components/example-nested/example-nested.js +10 -0
  237. package/src/wcs/components/example-routing/example-routing.js +51 -0
  238. package/src/wcs/components/example-rtl/example-rtl.js +28 -0
  239. package/src/wcs/components/example-tabs/example-tabs.js +12 -0
  240. package/src/wcs/components/example-web-component/example-web-component.js +34 -0
  241. package/src/wcs/components/floating-button/floating-button.js +17 -0
  242. package/src/wcs/components/formstack-form/fields/address.js +38 -0
  243. package/src/wcs/components/formstack-form/fields/checkbox.js +42 -0
  244. package/src/wcs/components/formstack-form/fields/date.js +22 -0
  245. package/src/wcs/components/formstack-form/fields/description.js +8 -0
  246. package/src/wcs/components/formstack-form/fields/input.js +8 -0
  247. package/src/wcs/components/formstack-form/fields/name.js +39 -0
  248. package/src/wcs/components/formstack-form/fields/radio.js +24 -0
  249. package/src/wcs/components/formstack-form/fields/rating.js +53 -0
  250. package/src/wcs/components/formstack-form/fields/section.js +8 -0
  251. package/src/wcs/components/formstack-form/fields/select.js +10 -0
  252. package/src/wcs/components/formstack-form/fields/textarea.js +8 -0
  253. package/src/wcs/components/formstack-form/fields/wrapper.js +11 -0
  254. package/src/wcs/components/formstack-form/formstack-form.js +280 -0
  255. package/src/wcs/components/fuel-prices/fuel-prices.js +45 -0
  256. package/src/wcs/components/furniture-overview/furniture-overview.js +115 -0
  257. package/src/wcs/components/gauge-value/gauge-value.js +65 -0
  258. package/src/wcs/components/help-centre/api.js +150 -0
  259. package/src/wcs/components/help-centre/help-centre.js +400 -0
  260. package/src/wcs/components/help-centre/icon-search.svg +1 -0
  261. package/src/wcs/components/image-gen/admin-panel.js +248 -0
  262. package/src/wcs/components/image-gen/image-gen.js +385 -0
  263. package/src/wcs/components/image-gen/labels.js +37 -0
  264. package/src/wcs/components/image-gen/use-api.js +392 -0
  265. package/src/wcs/components/inspired-gallery/inspired-gallery.js +118 -0
  266. package/src/wcs/components/launch-container/launch-container.js +95 -0
  267. package/src/wcs/components/launch-container/ledger.js +140 -0
  268. package/src/wcs/components/lng-map/lng-map.js +44 -0
  269. package/src/wcs/components/mouseflow-analytics/mouseflow-analytics.js +39 -0
  270. package/src/wcs/components/msds-search/msds-search.js +127 -0
  271. package/src/wcs/components/msds-search/navigation-search.svg +3 -0
  272. package/src/wcs/components/product-catalogue/icon-back.svg +3 -0
  273. package/src/wcs/components/product-catalogue/icon-cart.svg +3 -0
  274. package/src/wcs/components/product-catalogue/icon-close.svg +3 -0
  275. package/src/wcs/components/product-catalogue/product-catalogue.js +215 -0
  276. package/src/wcs/components/product-links/icon-cart.svg +3 -0
  277. package/src/wcs/components/product-links/product-links.js +43 -0
  278. package/src/wcs/components/rio-iframe/rio-iframe.js +137 -0
  279. package/src/wcs/components/salsify-products/filter-tools.js +60 -0
  280. package/src/wcs/components/salsify-products/icon-cart.svg +3 -0
  281. package/src/wcs/components/salsify-products/process-products.js +53 -0
  282. package/src/wcs/components/salsify-products/route-tools.js +54 -0
  283. package/src/wcs/components/salsify-products/salsify-products.js +281 -0
  284. package/src/wcs/components/shout-out/shout-out.js +51 -0
  285. package/src/wcs/components/simple-chart/simple-chart.js +53 -0
  286. package/src/wcs/components/single-stat/single-stat.js +85 -0
  287. package/src/wcs/components/site-feedback/site-feedback.js +56 -0
  288. package/src/wcs/components/skds-search/navigation-search.svg +3 -0
  289. package/src/wcs/components/skds-search/skds-search.js +103 -0
  290. package/src/wcs/components/smart-banner/smart-banner.js +104 -0
  291. package/src/wcs/components/standalone-table/arrow-up-down.svg +3 -0
  292. package/src/wcs/components/standalone-table/arrow-up.svg +3 -0
  293. package/src/wcs/components/standalone-table/standalone-table.js +440 -0
  294. package/src/wcs/components/station-locator/station-locator.js +49 -0
  295. package/src/wcs/components/store-badges/badges.js +60 -0
  296. package/src/wcs/components/store-badges/store-badges.js +93 -0
  297. package/src/wcs/components/topbar-button/person.svg +1 -0
  298. package/src/wcs/components/topbar-button/topbar-button.js +22 -0
  299. package/src/wcs/components/universal-gallery/universal-gallery.js +308 -0
  300. package/src/wcs/components/zendesk-chat/zendesk-chat.js +133 -0
  301. package/src/wcs/shared/chat-bot/README.md +61 -0
  302. package/src/wcs/shared/chat-bot/chat-bot.js +216 -0
  303. package/src/wcs/shared/chat-bot/resources/arrow-next.svg +1 -0
  304. package/src/wcs/shared/chat-bot/resources/navigation-close.svg +1 -0
  305. package/src/wcs/shared/chat-bot/resources/person.svg +1 -0
  306. package/src/wcs/shared/chat-bot/resources/upload.svg +1 -0
  307. package/src/wcs/shared/filtered-data/README.md +52 -0
  308. package/src/wcs/shared/filtered-data/fetch-data.js +33 -0
  309. package/src/wcs/shared/filtered-data/filtered-data.js +337 -0
  310. package/src/wcs/shared/promo-with-popup/icon-close.svg +3 -0
  311. package/src/wcs/shared/promo-with-popup/icon-next.svg +3 -0
  312. package/src/wcs/shared/promo-with-popup/icon-prev.svg +3 -0
  313. package/src/wcs/shared/promo-with-popup/promo-with-popup.js +93 -0
@@ -0,0 +1,224 @@
1
+ import { useRef, useLayoutEffect, useEffect } from 'preact/hooks'
2
+ import h from '../shared/h.js'
3
+ import { ARROW_BACK, ARROW_NEXT } from '../shared/icons.js'
4
+ import t from '../shared/t.js'
5
+ import { Button } from './button.js'
6
+ import { tw, LARGE, MEDIUM } from '../shared/twind.js'
7
+ import getSizeClass from '../shared/get-size-class.js'
8
+
9
+ // Sometimes navigating with a button does not cause the slider to scroll completely.
10
+ const RIGHT_BLUR_MARGIN_TOLERANCE = 2
11
+ const DEFAULT_COUNT = [3.25, 2.25, 1.25]
12
+
13
+ export function Scroller ({ _count, _tall, _index = 0, children, ...props }) {
14
+ const ref = useRef(null)
15
+ const {
16
+ _autoplay = false,
17
+ _interval = 3500,
18
+ _infinite = false,
19
+ _hideControls = false,
20
+ ...restProps
21
+ } = props
22
+ const baseSlides = children ?? []
23
+ const isInfinite = _infinite && baseSlides.length > 1
24
+ const slides = _infinite && baseSlides.length > 1
25
+ ? [...baseSlides, ...baseSlides, ...baseSlides]
26
+ : baseSlides
27
+ const interval = Math.max(1000, Number(_interval) || 3500)
28
+ const visibleSlideCount = _count ?? DEFAULT_COUNT
29
+ const [colsLarge, colsMedium, colsSmall] = visibleSlideCount
30
+ const blurSides = !visibleSlideCount.every(Number.isInteger)
31
+ const sizeClass = getSizeClass(_tall)
32
+
33
+ // Scroll to selected slide.
34
+ useLayoutEffect(() => {
35
+ if (ref.current) {
36
+ const container = ref.current
37
+ const startIndex = isInfinite ? baseSlides.length + _index : _index
38
+ const child = container.children[startIndex]
39
+ if (child) {
40
+ // Timeout fixes scroller in popup instances.
41
+ // We need to make sure the scroll is visible.
42
+ setTimeout(() => container.scrollTo({ left: child.offsetLeft }), 0)
43
+ }
44
+ }
45
+ }, [_index, isInfinite, baseSlides.length])
46
+
47
+ // Auto-scroll banners/slides and wrap seamlessly when infinite mode is enabled.
48
+ useEffect(() => {
49
+ if (!_autoplay || !ref.current || slides.length <= 1) {
50
+ return
51
+ }
52
+
53
+ const slider = ref.current
54
+ const timer = setInterval(() => {
55
+ const slideWidth = slider?.firstChild?.offsetWidth ?? 0
56
+ if (!slideWidth) {
57
+ return
58
+ }
59
+
60
+ const maxScrollLeft = Math.max(0, slider.scrollWidth - slider.clientWidth)
61
+ const nextLeft = slider.scrollLeft + slideWidth
62
+
63
+ if (isInfinite) {
64
+ const loopWidth = slider.children[baseSlides.length]?.offsetLeft ?? 0
65
+ const thirdSetStart = slider.children[baseSlides.length * 2]?.offsetLeft ?? maxScrollLeft
66
+ if (loopWidth > 0 && nextLeft >= thirdSetStart - RIGHT_BLUR_MARGIN_TOLERANCE) {
67
+ slider.scrollTo({ left: Math.max(0, nextLeft - loopWidth), behavior: 'auto' })
68
+ } else {
69
+ slider.scroll({ left: nextLeft, behavior: 'smooth' })
70
+ }
71
+ return
72
+ }
73
+
74
+ if (nextLeft >= maxScrollLeft - RIGHT_BLUR_MARGIN_TOLERANCE) {
75
+ slider.scrollTo({ left: 0, behavior: 'smooth' })
76
+ } else {
77
+ slider.scroll({ left: nextLeft, behavior: 'smooth' })
78
+ }
79
+ }, interval)
80
+
81
+ return () => clearInterval(timer)
82
+ }, [_autoplay, _infinite, interval, slides.length])
83
+
84
+ return h('div', {
85
+ ...restProps,
86
+ className: `flex flex-col ${sizeClass}`,
87
+ style: 'direction: ltr', // Do not mirror for RTL.
88
+ children: [
89
+ h('div', { className: 'relative grow' },
90
+ blurSides && h('div', { // Left blur
91
+ className: 'hidden absolute start-0 top-0 bottom-0 w-6 bg-bga rounded-tr-lg rounded-br-lg animate-fade',
92
+ style: 'background: linear-gradient(90deg, hsl(var(--color-bga)), transparent); pointer-events: none'
93
+ }),
94
+ h('div', {
95
+ ref,
96
+ className: 'w-full h-full overflow-x-scroll snap-x overflow-y-hidden grid grid-flow-col gap-5 outline-offset-1',
97
+ role: 'list',
98
+ onScroll (event) {
99
+ if (isInfinite) {
100
+ const slider = event.target
101
+ const loopWidth = slider.children[baseSlides.length]?.offsetLeft ?? 0
102
+ const maxScrollLeft = Math.max(0, slider.scrollWidth - slider.clientWidth)
103
+ const thirdSetStart = slider.children[baseSlides.length * 2]?.offsetLeft ?? maxScrollLeft
104
+
105
+ if (loopWidth > 0 && slider.scrollLeft <= RIGHT_BLUR_MARGIN_TOLERANCE) {
106
+ slider.scrollTo({ left: slider.scrollLeft + loopWidth, behavior: 'auto' })
107
+ } else if (loopWidth > 0 && slider.scrollLeft >= thirdSetStart - RIGHT_BLUR_MARGIN_TOLERANCE) {
108
+ slider.scrollTo({ left: Math.max(0, slider.scrollLeft - loopWidth), behavior: 'auto' })
109
+ }
110
+ }
111
+
112
+ if (!blurSides) {
113
+ return
114
+ }
115
+
116
+ const slider = event.target
117
+ if (slider.scrollLeft === 0) {
118
+ slider.parentElement.firstChild.classList.add(tw('hidden'))
119
+ } else if (slider.scrollLeft > slider.scrollWidth - slider.offsetWidth - RIGHT_BLUR_MARGIN_TOLERANCE) {
120
+ slider.parentElement.lastChild.classList.add(tw('hidden'))
121
+ } else {
122
+ slider.parentElement.firstChild.classList.remove(tw('hidden'))
123
+ slider.parentElement.lastChild.classList.remove(tw('hidden'))
124
+ }
125
+ },
126
+ _style: id => `
127
+ /* Firefox scrollbar cannot be styled, so hide it. */
128
+ @-moz-document url-prefix() ${id} {
129
+ scrollbar-width: none;
130
+ }
131
+
132
+ ${id} {
133
+ grid-auto-columns: ${getWidth(colsLarge)};
134
+ scrollbar-color: auto;
135
+ }
136
+
137
+ @media screen and (min-width: ${MEDIUM}px) and (max-width: ${LARGE - 1}px) {
138
+ ${id} { grid-auto-columns: ${getWidth(colsMedium)}; }
139
+ }
140
+
141
+ @media screen and (max-width: ${MEDIUM - 1}px) {
142
+ ${id} { grid-auto-columns: ${getWidth(colsSmall)}; }
143
+ }
144
+
145
+ ${id}::-webkit-scrollbar {
146
+ height: 24px;
147
+ background: transparent;
148
+ }
149
+
150
+ ${id}::-webkit-scrollbar-track {
151
+ background: transparent;
152
+ border-bottom: solid 4px hsla(var(--color-txa), 0.1);
153
+ }
154
+
155
+ ${id}::-webkit-scrollbar-thumb {
156
+ background: transparent;
157
+ border-bottom: solid 4px hsl(var(--color-bgb));
158
+ }
159
+
160
+ ${id} > div > * { height: 100%; }
161
+
162
+ /* Restore the RTL direction for slide content. */
163
+ [dir="rtl"] ${id} > div { direction: rtl; }
164
+ `,
165
+ children: slides.map(child =>
166
+ h('div', {
167
+ style: 'outline-offset: -1px',
168
+ role: 'listitem',
169
+ className: 'snap-start h-full',
170
+ children: child
171
+ })
172
+ )
173
+ }),
174
+ blurSides && h('div', { // Right blur
175
+ className: 'absolute end-0 top-0 bottom-0 w-6 bg-bga rounded-tl-lg rounded-bl-lg animate-fade',
176
+ style: 'background: linear-gradient(90deg, transparent, hsl(var(--color-bga))); pointer-events: none'
177
+ })
178
+ ),
179
+ !_hideControls && h('div', { className: 'gap-5 flex justify-end mt-5' },
180
+ h(Button, {
181
+ _model: { name: t('Previous slide'), icon: ARROW_BACK },
182
+ _textless: true,
183
+ tabindex: -1,
184
+ 'aria-hidden': true,
185
+ onClick: () => scroll(ref, -1, isInfinite, baseSlides.length)
186
+ }),
187
+ h(Button, {
188
+ _model: { name: t('Next slide'), icon: ARROW_NEXT },
189
+ _textless: true,
190
+ tabindex: -1,
191
+ 'aria-hidden': true,
192
+ onClick: () => scroll(ref, 1, isInfinite, baseSlides.length)
193
+ })
194
+ )
195
+ ]
196
+ })
197
+ }
198
+
199
+ function getWidth (visibleSlideCount) {
200
+ const gapCount = Math.ceil(visibleSlideCount) - 1
201
+ return `calc((100% - ${gapCount} * 20px) / ${visibleSlideCount})`
202
+ }
203
+
204
+ function scroll (ref, direction = 1, infinite = false, baseSlideCount = 0) {
205
+ const slider = ref?.current
206
+ const slideWidth = slider?.firstChild?.offsetWidth ?? 0
207
+ const pos = slider?.scrollLeft ?? 0
208
+ const nextPos = pos + direction * slideWidth
209
+
210
+ if (infinite && baseSlideCount > 1) {
211
+ const loopWidth = slider?.children?.[baseSlideCount]?.offsetLeft ?? 0
212
+ const thirdSetStart = slider?.children?.[baseSlideCount * 2]?.offsetLeft ?? 0
213
+ if (loopWidth > 0 && direction < 0 && nextPos <= RIGHT_BLUR_MARGIN_TOLERANCE) {
214
+ slider?.scrollTo({ left: pos + loopWidth, behavior: 'auto' })
215
+ return
216
+ }
217
+ if (loopWidth > 0 && thirdSetStart > 0 && direction > 0 && nextPos >= thirdSetStart - RIGHT_BLUR_MARGIN_TOLERANCE) {
218
+ slider?.scrollTo({ left: nextPos - loopWidth, behavior: 'auto' })
219
+ return
220
+ }
221
+ }
222
+
223
+ slider?.scroll({ left: nextPos, behavior: 'smooth' })
224
+ }
@@ -0,0 +1,65 @@
1
+ /* global DOMParser */
2
+ import { useEffect, useState } from 'preact/hooks'
3
+ import getSizeClass from '../shared/get-size-class.js'
4
+ import h from '../shared/h.js'
5
+ import { tw } from '../shared/twind.js'
6
+
7
+ // Cache SVGs to prevent flickering.
8
+ const cache = {}
9
+
10
+ export function SVG ({ _model, _tall, ...props }) {
11
+ const src = _model.src || ''
12
+ const alt = _model.alt || ''
13
+ const cacheKey = src + alt
14
+ const sizeClass = getSizeClass(_tall)
15
+ const [validSvg, setSvg] = useState(cache[cacheKey]) // Use the initial cached value.
16
+
17
+ // The src might have changed. Use the current cached value.
18
+ setSvg(cache[cacheKey])
19
+
20
+ useEffect(() => {
21
+ // Fetch if not cached.
22
+ validSvg || (async function () {
23
+ const isLink = src.endsWith('.svg') || src.startsWith('data:')
24
+ const rawSvg = isLink ? await fetchSvg(src) : src
25
+ cache[cacheKey] = getSvg(rawSvg, sizeClass, alt)
26
+ setSvg(cache[cacheKey])
27
+ })()
28
+ }, [src, alt, sizeClass])
29
+
30
+ return validSvg
31
+ ? h('div', { ...props, className: `${sizeClass}`, dangerouslySetInnerHTML: { __html: validSvg } })
32
+ : null
33
+ }
34
+
35
+ function getSvg (svgContent, sizeClass, alt) {
36
+ const svgDoc = (new DOMParser()).parseFromString(svgContent, 'image/svg+xml')
37
+ const parserError = svgDoc.getElementsByTagName('parsererror')[0]
38
+
39
+ if (parserError) {
40
+ console.warn(`Invalid SVG: ${svgContent}\n${parserError.innerText}`)
41
+ return null
42
+ }
43
+
44
+ const svgEl = svgDoc.documentElement
45
+ svgEl.setAttribute('class', tw(`block ${sizeClass}`))
46
+
47
+ // Treat it like an image if alt is provided.
48
+ if (alt) {
49
+ svgEl.setAttribute('role', 'img')
50
+ svgEl.setAttribute('title', alt)
51
+ }
52
+
53
+ return svgEl.outerHTML
54
+ }
55
+
56
+ async function fetchSvg (url) {
57
+ try {
58
+ const res = await fetch(url)
59
+ return res.text()
60
+ } catch (error) {
61
+ console.warn('Unable to fetch SVG:', url)
62
+ console.warn(error)
63
+ return null
64
+ }
65
+ }
@@ -0,0 +1,32 @@
1
+ import h from '../shared/h.js'
2
+
3
+ export function Table ({ children, ...props }) {
4
+ return h('div', { ...props, className: 'overflow-x-auto' }, // Make it scrollable.
5
+ h('table', {
6
+ className: 'rounded-lg border-l border-t border-spacing-0 border-txa/20 border-separate w-full',
7
+ _style: id => `
8
+ ${id} tr { width: 100% }
9
+ ${id} tr:hover { background-color: hsla(var(--color-txa), 0.05) }
10
+ ${id} td, th {
11
+ text-align: left;
12
+ vertical-align: top;
13
+ padding: calc(8px);
14
+ border-right: 1px solid hsla(var(--color-txa), 0.2);
15
+ border-bottom: 1px solid hsla(var(--color-txa), 0.2);
16
+ }
17
+ ${id} th > *, td > * {
18
+ vertical-align: top;
19
+ }
20
+ ${id} th {
21
+ font-weight: bold;
22
+ background-color: hsla(var(--color-txa), 0.05);
23
+ }
24
+ ${id} tr:first-child > *:first-child { border-top-left-radius: 8px }
25
+ ${id} tr:first-child > *:last-child { border-top-right-radius: 8px }
26
+ ${id} tr:last-child > *:first-child { border-bottom-left-radius: 8px }
27
+ ${id} tr:last-child > *:last-child { border-bottom-right-radius: 8px }
28
+ `,
29
+ children
30
+ })
31
+ )
32
+ }
@@ -0,0 +1,10 @@
1
+ import h from '../shared/h.js'
2
+
3
+ export function Textarea (props) {
4
+ return h('textarea', {
5
+ ...props,
6
+ style: 'resize: vertical',
7
+ // Force input colour to brand1.
8
+ className: 'pal-brand1 block rounded-lg bg-bga text-txa border-txa/20 w-full p-4 border h-36'
9
+ })
10
+ }
@@ -0,0 +1,12 @@
1
+ import h from '../shared/h.js'
2
+ import formatTime from '../shared/format-time.js'
3
+
4
+ export function Time ({ _time, ...props }) {
5
+ const date = new Date(_time || Date.now())
6
+ return h('time', {
7
+ ...props,
8
+ className: 'block text-txa/80',
9
+ datetime: date.toISOString(),
10
+ children: formatTime(date)
11
+ })
12
+ }
@@ -0,0 +1,100 @@
1
+ import { useRef, useState } from 'preact/hooks'
2
+ import bubbleEvent from '../shared/bubble-event.js'
3
+ import getId from '../shared/get-id.js'
4
+ import getSizeClass from '../shared/get-size-class.js'
5
+ import h from '../shared/h.js'
6
+ import { MEDIA_PAUSE, MEDIA_PLAY } from '../shared/icons.js'
7
+ import t from '../shared/t.js'
8
+ import { Button } from './button.js'
9
+
10
+ export function Video ({ _model, _tall, _fit, ...props }) {
11
+ const { src } = _model
12
+
13
+ if (!src) {
14
+ return null
15
+ }
16
+
17
+ const url = new URL(src, globalThis.origin)
18
+ const Handler = globalThis.origin === url.origin ? HTMLVideo : EmbedVideo
19
+ return h(Handler, { _model, _tall, _fit, ...props })
20
+ }
21
+
22
+ function EmbedVideo ({ _model, _tall, ...props }) {
23
+ const { src, caption, autoplay } = _model
24
+ const url = new URL(src)
25
+ const sizeClass = getSizeClass(_tall)
26
+ const [id] = useState(() => getId())
27
+
28
+ // Support for YouTube background videos.
29
+ const ytVideoId = src.replace(/https:\/\/(?:www\.)?(?:youtube\.com|youtube-nocookie\.com)\/embed\/([a-z0-9-_]{11})/i, '$1')
30
+
31
+ // Enable JS API to allow postMessage control of the video for YouTube videos.
32
+ url.searchParams.set('enablejsapi', 1)
33
+ if (ytVideoId && autoplay) {
34
+ url.searchParams.set('autoplay', 1)
35
+ url.searchParams.set('playsinline', 1)
36
+ url.searchParams.set('loop', 1)
37
+ url.searchParams.set('mute', 1)
38
+ url.searchParams.set('controls', 0)
39
+ url.searchParams.set('playlist', ytVideoId)
40
+ }
41
+
42
+ // Iframe needs a default aspect ratio.
43
+ return h('iframe', {
44
+ ...props,
45
+ id,
46
+ className: `block aspect-video ${sizeClass}`,
47
+ onLoad: bubbleEvent,
48
+ loading: 'lazy',
49
+ src: url.href,
50
+ title: caption,
51
+ allow: 'accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture',
52
+ allowFullScreen: true
53
+ })
54
+ }
55
+
56
+ // iOS is very particular about the videos:
57
+ // https://webkit.org/blog/6784/new-video-policies-for-ios/
58
+ function HTMLVideo ({ _model, _tall, _fit = 'cover', ...props }) {
59
+ const { src, caption, autoplay } = _model
60
+
61
+ const msgPause = t('Pause playback')
62
+ const msgPlay = t('Resume playback')
63
+ const sizeClass = getSizeClass(_tall)
64
+ const fitClass = `object-${_fit}`
65
+ const [state, setState] = useState({ icon: MEDIA_PAUSE, text: msgPause })
66
+ const ref = useRef(null)
67
+
68
+ return h('div', { ...props, className: `relative ${sizeClass}` },
69
+ h('video', {
70
+ ref,
71
+ autoplay,
72
+ className: `block ${sizeClass} ${fitClass}`,
73
+ controls: !autoplay,
74
+ title: caption,
75
+ loop: autoplay,
76
+ muted: autoplay, // https://stackoverflow.com/questions/61510160/why-muted-attribute-on-video-tag-is-ignored-in-react
77
+ playsinline: autoplay,
78
+ onTimeUpdate: bubbleEvent,
79
+ children: h('source', { src })
80
+ }),
81
+ autoplay && h('div', { className: 'absolute top-4 end-4' },
82
+ h(Button, {
83
+ _variant: 'plain',
84
+ _textless: true,
85
+ _size: 'sm',
86
+ _color: 'transparent',
87
+ _model: { name: state.text, icon: state.icon },
88
+ onClick: () => {
89
+ if (ref.current.paused) {
90
+ ref.current.play()
91
+ setState({ icon: MEDIA_PAUSE, text: msgPause })
92
+ } else {
93
+ ref.current.pause()
94
+ setState({ icon: MEDIA_PLAY, text: msgPlay })
95
+ }
96
+ }
97
+ })
98
+ )
99
+ )
100
+ }
@@ -0,0 +1,12 @@
1
+ export { componentModels } from './routing/component.js'
2
+ export { ValidationError } from './routing/error-handler.js'
3
+ export { dataset } from './routing/router.js'
4
+ export { getUserId } from './shared/analytics.js'
5
+ export { default as customElement } from './shared/custom-element.js'
6
+ export { default as h } from './shared/h.js'
7
+ export { default as register } from './shared/register.js'
8
+ export { renderComponent, renderPage } from './shared/renderer.js'
9
+ export { getConsent, setConsent, waitForConsent } from './shared/simple-consent-api.js'
10
+ export { i18n, default as t } from './shared/t.js'
11
+ export { injectStyles, LARGE, MEDIUM, tw } from './shared/twind.js'
12
+ export { default as deepSelector } from './shared/deep-selector.js'
@@ -0,0 +1,86 @@
1
+ // Atoms
2
+ export { Audio } from './atoms/audio.js'
3
+ export { Box } from './atoms/box.js'
4
+ export { Button } from './atoms/button.js'
5
+ export { Card } from './atoms/card.js'
6
+ export { Form } from './atoms/form.js'
7
+ export { Heading } from './atoms/heading.js'
8
+ export { Icon } from './atoms/icon.js'
9
+ export { Input } from './atoms/input.js'
10
+ export { Img } from './atoms/img.js'
11
+ export { Link } from './atoms/link.js'
12
+ export { List } from './atoms/list.js'
13
+ export { LinkText } from './atoms/link-text.js'
14
+ export { Logo } from './atoms/logo.js'
15
+ export { Menu } from './atoms/menu.js'
16
+ export { Message } from './atoms/message.js'
17
+ export { NavLink } from './atoms/nav-link.js'
18
+ export { Popup } from './atoms/popup.js'
19
+ export { RichText } from './atoms/rich-text.js'
20
+ export { Scroller } from './atoms/scroller.js'
21
+ export { SVG } from './atoms/svg.js'
22
+ export { Table } from './atoms/table.js'
23
+ export { Time } from './atoms/time.js'
24
+ export { Video } from './atoms/video.js'
25
+
26
+ // Molecules
27
+ export { Asset } from './molecules/asset.js'
28
+ export { Glossary } from './molecules/glossary.js'
29
+ export { Links } from './molecules/links.js'
30
+ export { PromoText } from './molecules/promo-text.js'
31
+ export { Tags } from './molecules/tags.js'
32
+ export { Tree } from './molecules/tree.js'
33
+
34
+ // Organisms
35
+ export { AccordionItem } from './organisms/accordion-item.js'
36
+ export { Author } from './organisms/author.js'
37
+ export { Breadcrumb } from './organisms/breadcrumb.js'
38
+ export { CallToAction } from './organisms/call-to-action.js'
39
+ export { Carousel } from './organisms/carousel.js'
40
+ export { CartItem } from './organisms/cart-item.js'
41
+ export { Cart } from './organisms/cart.js'
42
+ export { ContactForm } from './organisms/contact-form.js'
43
+ export { Container } from './organisms/container.js'
44
+ export { ContentOwner } from './organisms/content-owner.js'
45
+ export { DateEntry } from './organisms/date-entry.js'
46
+ export { ExternalSearch } from './organisms/external-search.js'
47
+ export { FilteredItem } from './organisms/filtered-item.js'
48
+ export { FooterItem } from './organisms/footer-item.js'
49
+ export { ImageGallery } from './organisms/image-gallery.js'
50
+ export { LastModified } from './organisms/last-modified.js'
51
+ export { LegalFooter } from './organisms/legal-footer.js'
52
+ export { ListItem } from './organisms/list-item.js'
53
+ export { Metadata } from './organisms/metadata.js'
54
+ export { Navigation } from './organisms/navigation.js'
55
+ export { Notification } from './organisms/notification.js'
56
+ export { OrderTracker } from './organisms/order-tracker.js'
57
+ export { Page } from './organisms/page.js'
58
+ export { PageHeader } from './organisms/page-header.js'
59
+ export { PageHeaderBanner } from './organisms/page-header-banner.js'
60
+ export { PageTags } from './organisms/page-tags.js'
61
+ export { PressRelease } from './organisms/press-release.js'
62
+ export { PromoBanner } from './organisms/promo-banner.js'
63
+ export { PromoBottom } from './organisms/promo-bottom.js'
64
+ export { PromoButton } from './organisms/promo-button.js'
65
+ export { PromoCard } from './organisms/promo-card.js'
66
+ export { PromoCardCover } from './organisms/promo-card-cover.js'
67
+ export { PromoProductCard } from './organisms/promo-product-card.js'
68
+ export { PromoProductFull } from './organisms/promo-product-full.js'
69
+ export { ProductAdmin } from './organisms/product-admin.js'
70
+ export { PromoFull } from './organisms/promo-full.js'
71
+ export { PromoLure } from './organisms/promo-lure.js'
72
+ export { PromoSimple } from './organisms/promo-simple.js'
73
+ export { PromoImage } from './organisms/promo-image.js'
74
+ export { Quote } from './organisms/quote.js'
75
+ export { SearchForm } from './organisms/search-form.js'
76
+ export { SearchResult } from './organisms/search-result.js'
77
+ export { SearchNav } from './organisms/search-nav.js'
78
+ export { Slider } from './organisms/slider.js'
79
+ export { StandaloneAsset } from './organisms/standalone-asset.js'
80
+ export { Tabs } from './organisms/tabs.js'
81
+ export { Topbar } from './organisms/topbar.js'
82
+ export { WebComponent } from './organisms/web-component.js'
83
+
84
+ // Routing
85
+ export { Component } from './routing/component.js'
86
+ export { Router } from './routing/router.js'
@@ -0,0 +1 @@
1
+ export * from 'preact/hooks'
@@ -0,0 +1 @@
1
+ export * from 'preact'
@@ -0,0 +1,13 @@
1
+ /* global ACINGUIUX_PREACT_VERSION */
2
+ import * as main from './export-main.js'
3
+ import * as matter from './export-matter.js'
4
+ import * as preact from './export-preact.js'
5
+ import * as preactHooks from './export-preact-hooks.js'
6
+
7
+ export * from './export-main.js'
8
+ export * as matter from './export-matter.js'
9
+ export * as preact from './export-preact.js'
10
+ export * as preactHooks from './export-preact-hooks.js'
11
+
12
+ globalThis.ami = { ...main, matter, preact, preactHooks, version: ACINGUIUX_PREACT_VERSION }
13
+ main.renderPage()
@@ -0,0 +1,23 @@
1
+ import { Img } from '../atoms/img.js'
2
+ import { SVG } from '../atoms/svg.js'
3
+ import { Video } from '../atoms/video.js'
4
+ import { Audio } from '../atoms/audio.js'
5
+ import h from '../shared/h.js'
6
+
7
+ const AUDIO_EXTENSIONS = ['.mp3', '.m4a', '.ogg', '.wav', '.aac', '.flac']
8
+
9
+ export function Asset ({ _model, _tall, _fit, ...props }) {
10
+ const { image, video } = _model
11
+
12
+ if (AUDIO_EXTENSIONS.some(ext => video.src?.toLowerCase().endsWith(ext))) {
13
+ return h(Audio, { _model: video, ...props })
14
+ }
15
+
16
+ if (video.src) {
17
+ return h(Video, { ...props, _model: video, _tall, _fit })
18
+ }
19
+
20
+ return image.src?.toLowerCase().endsWith('.svg')
21
+ ? h(SVG, { ...props, _model: image, _tall })
22
+ : h(Img, { ...props, _model: image, _tall, _fit })
23
+ }
@@ -0,0 +1,44 @@
1
+ import { Link } from '../atoms/link.js'
2
+ import { RichText } from '../atoms/rich-text.js'
3
+ import { Table } from '../atoms/table.js'
4
+ import { Asset } from '../molecules/asset.js'
5
+ import formatTime from '../shared/format-time.js'
6
+ import h from '../shared/h.js'
7
+
8
+ export function Glossary ({ _model, ...props }) {
9
+ const { title, text, tags, links, image, video, asset, date } = _model
10
+
11
+ const list = []
12
+ title && list.push({ name: 'title', value: title })
13
+ text && list.push({ name: 'text', value: h(RichText, text) })
14
+ date && list.push({ name: 'date', value: formatTime(date) })
15
+ tags.length > 0 && list.push({ name: 'tags', value: tags.map(t => t.name).join(', ') })
16
+
17
+ list.push(...links.map((l, ii) => ({
18
+ name: `link\u00A0${ii + 1}`,
19
+ value: h(Link, { _model: { ...l, name: `${l.name} (${l.value})` } })
20
+ })))
21
+
22
+ const hasAsset = asset?.src
23
+ return h('div', { ...props, className: 'grid gap-5 grid-cols-12 px-6 py-4 text-sm bg-bga text-txa w-full' },
24
+ list.length === 0 && h('div', { className: 'col-span-12' }, 'No data'),
25
+ list.length > 0 && [
26
+ h('div', { className: hasAsset ? 'col-span-10' : 'col-span-12' },
27
+ h(Table,
28
+ h('tbody', list.map(item =>
29
+ h('tr', [
30
+ h('th', item.name),
31
+ h('td', item.value)
32
+ ])
33
+ ))
34
+ )
35
+ ),
36
+ hasAsset && h('figure', { className: 'col-span-2 space-y-1' },
37
+ h('div', { className: 'rounded-lg overflow-hidden' },
38
+ h(Asset, { _model: { image, video } })
39
+ ),
40
+ asset.caption && h('figcaption', asset.caption)
41
+ )
42
+ ]
43
+ )
44
+ }
@@ -0,0 +1,23 @@
1
+ import { Button } from '../atoms/button.js'
2
+ import { Link } from '../atoms/link.js'
3
+ import h from '../shared/h.js'
4
+
5
+ export function Links ({ _model, _variant, ...props }) {
6
+ const { links } = _model
7
+
8
+ if (links.length === 0) {
9
+ return null
10
+ }
11
+
12
+ // Render as button if one link is present.
13
+ if (links.length === 1 && !_variant) {
14
+ return h(Button, { _model: links[0] })
15
+ }
16
+
17
+ // Render as list of links if more than one link.
18
+ return h('div', { ...props, role: 'list', className: 'space-y-2' }, links.map(link =>
19
+ h('div', { role: 'listitem' },
20
+ h(Link, { _model: link, _variant: _variant ?? 'full' })
21
+ )
22
+ ))
23
+ }