@pixelated-tech/components 3.4.2 → 3.5.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 (235) hide show
  1. package/README.md +32 -191
  2. package/dist/components/admin/componentusage/componentAnalysis.js +12 -4
  3. package/dist/components/admin/componentusage/componentDiscovery.js +20 -6
  4. package/dist/components/admin/site-health/seo-metrics.config.json +111 -0
  5. package/dist/components/admin/site-health/site-health-accessibility.js +5 -1
  6. package/dist/components/admin/site-health/site-health-axe-core.js +4 -0
  7. package/dist/components/admin/site-health/site-health-cloudwatch.integration.js +0 -5
  8. package/dist/components/admin/site-health/site-health-cloudwatch.js +7 -1
  9. package/dist/components/admin/site-health/site-health-dependency-vulnerabilities.js +4 -0
  10. package/dist/components/admin/site-health/site-health-github.js +6 -0
  11. package/dist/components/admin/site-health/site-health-google-analytics.js +6 -0
  12. package/dist/components/admin/site-health/site-health-google-search-console.js +6 -0
  13. package/dist/components/admin/site-health/site-health-on-site-seo.integration.js +379 -12
  14. package/dist/components/admin/site-health/site-health-on-site-seo.js +4 -0
  15. package/dist/components/admin/site-health/site-health-overview.js +11 -4
  16. package/dist/components/admin/site-health/site-health-performance.js +4 -0
  17. package/dist/components/admin/site-health/site-health-security.js +5 -1
  18. package/dist/components/admin/site-health/site-health-seo.js +5 -1
  19. package/dist/components/admin/site-health/site-health-template.js +19 -9
  20. package/dist/components/admin/site-health/site-health-uptime.js +4 -0
  21. package/dist/components/callout/callout.js +0 -10
  22. package/dist/components/carousel/carousel.js +15 -4
  23. package/dist/components/carousel/tiles.js +1 -1
  24. package/dist/components/cms/contentful.items.components.js +3 -4
  25. package/dist/components/cms/flickr.js +1 -1
  26. package/dist/components/cms/google.reviews.components.js +3 -3
  27. package/dist/components/cms/instagram.components.js +15 -5
  28. package/dist/components/cms/smartimage.js +2 -2
  29. package/dist/components/cms/wordpress.components.js +32 -6
  30. package/dist/components/cms/yelp.js +5 -0
  31. package/dist/components/config/config.server.js +7 -1
  32. package/dist/components/general/css.js +0 -1
  33. package/dist/components/general/image.js +0 -1
  34. package/dist/components/general/loading.js +2 -1
  35. package/dist/components/general/microinteractions.js +0 -1
  36. package/dist/components/general/modal.css +2 -4
  37. package/dist/components/general/modal.js +72 -30
  38. package/dist/components/general/sidepanel.js +16 -0
  39. package/dist/components/general/tab.js +1 -0
  40. package/dist/components/menu/menu-accordion.css +1 -1
  41. package/dist/components/menu/menu-accordion.js +15 -4
  42. package/dist/components/menu/menu-expando.js +21 -19
  43. package/dist/components/menu/menu-simple.js +14 -14
  44. package/dist/components/nerdjoke/nerdjoke.js +1 -1
  45. package/dist/components/seo/googlesearch.js +0 -1
  46. package/dist/components/seo/schema-blogposting.js +6 -1
  47. package/dist/components/seo/schema-recipe.js +34 -1
  48. package/dist/components/seo/schema-services.js +20 -2
  49. package/dist/components/shoppingcart/ebay.components.js +3 -3
  50. package/dist/components/shoppingcart/shoppingcart.components.js +76 -28
  51. package/dist/components/shoppingcart/shoppingcart.functions.js +4 -4
  52. package/dist/components/sitebuilder/config/CompoundFontSelector.js +13 -4
  53. package/dist/components/sitebuilder/config/ConfigBuilder.css +194 -5
  54. package/dist/components/sitebuilder/config/ConfigBuilder.js +183 -17
  55. package/dist/components/sitebuilder/config/FontSelector.js +13 -2
  56. package/dist/components/sitebuilder/config/routes-form.json +67 -0
  57. package/dist/components/sitebuilder/config/siteinfo-form.json +28 -14
  58. package/dist/components/sitebuilder/config/visualdesignform.json +4 -4
  59. package/dist/components/sitebuilder/form/formbuilder.js +1 -0
  60. package/dist/components/sitebuilder/form/formcomponents.js +2 -3
  61. package/dist/components/sitebuilder/form/formengine.js +6 -5
  62. package/dist/components/sitebuilder/form/formvalidator.js +5 -0
  63. package/dist/components/sitebuilder/page/components/PageBuilderUI.js +5 -1
  64. package/dist/components/structured/buzzwordbingo.css +0 -1
  65. package/dist/components/structured/recipe.js +1 -1
  66. package/dist/components/structured/socialcard.js +2 -2
  67. package/dist/components/utilities/functions.js +82 -1
  68. package/dist/components/utilities/gemini-api.client.js +76 -0
  69. package/dist/components/utilities/gemini-api.server.js +185 -0
  70. package/dist/data/routes.json +5 -5
  71. package/dist/index.adminclient.js +30 -0
  72. package/dist/index.adminserver.js +21 -0
  73. package/dist/index.js +4 -18
  74. package/dist/index.server.js +15 -28
  75. package/dist/types/components/admin/componentusage/componentAnalysis.d.ts.map +1 -1
  76. package/dist/types/components/admin/componentusage/componentDiscovery.d.ts +1 -1
  77. package/dist/types/components/admin/componentusage/componentDiscovery.d.ts.map +1 -1
  78. package/dist/types/components/admin/site-health/site-health-accessibility.d.ts +7 -4
  79. package/dist/types/components/admin/site-health/site-health-accessibility.d.ts.map +1 -1
  80. package/dist/types/components/admin/site-health/site-health-axe-core.d.ts +7 -4
  81. package/dist/types/components/admin/site-health/site-health-axe-core.d.ts.map +1 -1
  82. package/dist/types/components/admin/site-health/site-health-cloudwatch.d.ts +9 -6
  83. package/dist/types/components/admin/site-health/site-health-cloudwatch.d.ts.map +1 -1
  84. package/dist/types/components/admin/site-health/site-health-cloudwatch.integration.d.ts.map +1 -1
  85. package/dist/types/components/admin/site-health/site-health-dependency-vulnerabilities.d.ts +7 -4
  86. package/dist/types/components/admin/site-health/site-health-dependency-vulnerabilities.d.ts.map +1 -1
  87. package/dist/types/components/admin/site-health/site-health-github.d.ts +9 -6
  88. package/dist/types/components/admin/site-health/site-health-github.d.ts.map +1 -1
  89. package/dist/types/components/admin/site-health/site-health-google-analytics.d.ts +9 -6
  90. package/dist/types/components/admin/site-health/site-health-google-analytics.d.ts.map +1 -1
  91. package/dist/types/components/admin/site-health/site-health-google-search-console.d.ts +9 -6
  92. package/dist/types/components/admin/site-health/site-health-google-search-console.d.ts.map +1 -1
  93. package/dist/types/components/admin/site-health/site-health-on-site-seo.d.ts +8 -3
  94. package/dist/types/components/admin/site-health/site-health-on-site-seo.d.ts.map +1 -1
  95. package/dist/types/components/admin/site-health/site-health-on-site-seo.integration.d.ts.map +1 -1
  96. package/dist/types/components/admin/site-health/site-health-overview.d.ts +7 -4
  97. package/dist/types/components/admin/site-health/site-health-overview.d.ts.map +1 -1
  98. package/dist/types/components/admin/site-health/site-health-performance.d.ts +7 -4
  99. package/dist/types/components/admin/site-health/site-health-performance.d.ts.map +1 -1
  100. package/dist/types/components/admin/site-health/site-health-security.d.ts +7 -4
  101. package/dist/types/components/admin/site-health/site-health-security.d.ts.map +1 -1
  102. package/dist/types/components/admin/site-health/site-health-seo.d.ts +7 -4
  103. package/dist/types/components/admin/site-health/site-health-seo.d.ts.map +1 -1
  104. package/dist/types/components/admin/site-health/site-health-template.d.ts +12 -10
  105. package/dist/types/components/admin/site-health/site-health-template.d.ts.map +1 -1
  106. package/dist/types/components/admin/site-health/site-health-uptime.d.ts +7 -4
  107. package/dist/types/components/admin/site-health/site-health-uptime.d.ts.map +1 -1
  108. package/dist/types/components/callout/callout.d.ts +3 -3
  109. package/dist/types/components/callout/callout.d.ts.map +1 -1
  110. package/dist/types/components/carousel/carousel.d.ts +16 -7
  111. package/dist/types/components/carousel/carousel.d.ts.map +1 -1
  112. package/dist/types/components/carousel/tiles.d.ts +3 -6
  113. package/dist/types/components/carousel/tiles.d.ts.map +1 -1
  114. package/dist/types/components/cms/flickr.d.ts +3 -6
  115. package/dist/types/components/cms/flickr.d.ts.map +1 -1
  116. package/dist/types/components/cms/google.reviews.components.d.ts +1 -7
  117. package/dist/types/components/cms/google.reviews.components.d.ts.map +1 -1
  118. package/dist/types/components/cms/hubspot.components.d.ts +1 -2
  119. package/dist/types/components/cms/hubspot.components.d.ts.map +1 -1
  120. package/dist/types/components/cms/instagram.components.d.ts +14 -9
  121. package/dist/types/components/cms/instagram.components.d.ts.map +1 -1
  122. package/dist/types/components/cms/smartimage.d.ts +2 -28
  123. package/dist/types/components/cms/smartimage.d.ts.map +1 -1
  124. package/dist/types/components/cms/wordpress.components.d.ts +33 -14
  125. package/dist/types/components/cms/wordpress.components.d.ts.map +1 -1
  126. package/dist/types/components/cms/yelp.d.ts +9 -4
  127. package/dist/types/components/cms/yelp.d.ts.map +1 -1
  128. package/dist/types/components/config/config.server.d.ts +9 -6
  129. package/dist/types/components/config/config.server.d.ts.map +1 -1
  130. package/dist/types/components/general/loading.d.ts +5 -1
  131. package/dist/types/components/general/loading.d.ts.map +1 -1
  132. package/dist/types/components/general/microinteractions.d.ts +1 -3
  133. package/dist/types/components/general/microinteractions.d.ts.map +1 -1
  134. package/dist/types/components/general/modal.d.ts +11 -5
  135. package/dist/types/components/general/modal.d.ts.map +1 -1
  136. package/dist/types/components/general/semantic.d.ts +3 -3
  137. package/dist/types/components/general/sidepanel.d.ts +20 -13
  138. package/dist/types/components/general/sidepanel.d.ts.map +1 -1
  139. package/dist/types/components/general/tab.d.ts +1 -2
  140. package/dist/types/components/general/tab.d.ts.map +1 -1
  141. package/dist/types/components/menu/menu-accordion.d.ts +22 -9
  142. package/dist/types/components/menu/menu-accordion.d.ts.map +1 -1
  143. package/dist/types/components/menu/menu-expando.d.ts +14 -5
  144. package/dist/types/components/menu/menu-expando.d.ts.map +1 -1
  145. package/dist/types/components/menu/menu-simple.d.ts +4 -5
  146. package/dist/types/components/menu/menu-simple.d.ts.map +1 -1
  147. package/dist/types/components/nerdjoke/nerdjoke.d.ts +1 -1
  148. package/dist/types/components/nerdjoke/nerdjoke.d.ts.map +1 -1
  149. package/dist/types/components/seo/googleanalytics.d.ts.map +1 -1
  150. package/dist/types/components/seo/metadata.components.d.ts +2 -2
  151. package/dist/types/components/seo/metadata.components.d.ts.map +1 -1
  152. package/dist/types/components/seo/schema-blogposting.d.ts +7 -4
  153. package/dist/types/components/seo/schema-blogposting.d.ts.map +1 -1
  154. package/dist/types/components/seo/schema-recipe.d.ts +29 -30
  155. package/dist/types/components/seo/schema-recipe.d.ts.map +1 -1
  156. package/dist/types/components/seo/schema-services.d.ts +19 -9
  157. package/dist/types/components/seo/schema-services.d.ts.map +1 -1
  158. package/dist/types/components/shoppingcart/paypal.d.ts +1 -1
  159. package/dist/types/components/shoppingcart/paypal.d.ts.map +1 -1
  160. package/dist/types/components/shoppingcart/shoppingcart.components.d.ts +77 -28
  161. package/dist/types/components/shoppingcart/shoppingcart.components.d.ts.map +1 -1
  162. package/dist/types/components/shoppingcart/shoppingcart.functions.d.ts +4 -23
  163. package/dist/types/components/shoppingcart/shoppingcart.functions.d.ts.map +1 -1
  164. package/dist/types/components/sitebuilder/config/CompoundFontSelector.d.ts +10 -11
  165. package/dist/types/components/sitebuilder/config/CompoundFontSelector.d.ts.map +1 -1
  166. package/dist/types/components/sitebuilder/config/ConfigBuilder.d.ts +41 -174
  167. package/dist/types/components/sitebuilder/config/ConfigBuilder.d.ts.map +1 -1
  168. package/dist/types/components/sitebuilder/config/FontSelector.d.ts +12 -13
  169. package/dist/types/components/sitebuilder/config/FontSelector.d.ts.map +1 -1
  170. package/dist/types/components/sitebuilder/form/formbuilder.d.ts +7 -3
  171. package/dist/types/components/sitebuilder/form/formbuilder.d.ts.map +1 -1
  172. package/dist/types/components/sitebuilder/form/formcomponents.d.ts +1 -1
  173. package/dist/types/components/sitebuilder/form/formcomponents.d.ts.map +1 -1
  174. package/dist/types/components/sitebuilder/form/formengine.d.ts +1 -2
  175. package/dist/types/components/sitebuilder/form/formengine.d.ts.map +1 -1
  176. package/dist/types/components/sitebuilder/form/formextractor.d.ts +5 -4
  177. package/dist/types/components/sitebuilder/form/formextractor.d.ts.map +1 -1
  178. package/dist/types/components/sitebuilder/form/formtypes.d.ts +3 -3
  179. package/dist/types/components/sitebuilder/form/formtypes.d.ts.map +1 -1
  180. package/dist/types/components/sitebuilder/form/formvalidator.d.ts +8 -3
  181. package/dist/types/components/sitebuilder/form/formvalidator.d.ts.map +1 -1
  182. package/dist/types/components/sitebuilder/page/components/ComponentPropertiesForm.d.ts +2 -3
  183. package/dist/types/components/sitebuilder/page/components/ComponentPropertiesForm.d.ts.map +1 -1
  184. package/dist/types/components/sitebuilder/page/components/ComponentSelector.d.ts +2 -3
  185. package/dist/types/components/sitebuilder/page/components/ComponentSelector.d.ts.map +1 -1
  186. package/dist/types/components/sitebuilder/page/components/ComponentTree.d.ts +2 -3
  187. package/dist/types/components/sitebuilder/page/components/ComponentTree.d.ts.map +1 -1
  188. package/dist/types/components/sitebuilder/page/components/PageBuilderUI.d.ts +8 -7
  189. package/dist/types/components/sitebuilder/page/components/PageBuilderUI.d.ts.map +1 -1
  190. package/dist/types/components/sitebuilder/page/components/PageEngine.d.ts.map +1 -1
  191. package/dist/types/components/sitebuilder/page/components/SaveLoadSection.d.ts +2 -3
  192. package/dist/types/components/sitebuilder/page/components/SaveLoadSection.d.ts.map +1 -1
  193. package/dist/types/components/sitebuilder/page/lib/componentMap.d.ts +1 -1
  194. package/dist/types/components/structured/markdown.d.ts +1 -3
  195. package/dist/types/components/structured/markdown.d.ts.map +1 -1
  196. package/dist/types/components/structured/recipe.d.ts +5 -32
  197. package/dist/types/components/structured/recipe.d.ts.map +1 -1
  198. package/dist/types/components/structured/socialcard.d.ts +4 -0
  199. package/dist/types/components/structured/socialcard.d.ts.map +1 -1
  200. package/dist/types/components/structured/timeline.d.ts +1 -3
  201. package/dist/types/components/structured/timeline.d.ts.map +1 -1
  202. package/dist/types/components/utilities/functions.d.ts +20 -0
  203. package/dist/types/components/utilities/functions.d.ts.map +1 -1
  204. package/dist/types/components/utilities/gemini-api.client.d.ts +38 -0
  205. package/dist/types/components/utilities/gemini-api.client.d.ts.map +1 -0
  206. package/dist/types/components/utilities/gemini-api.server.d.ts +17 -0
  207. package/dist/types/components/utilities/gemini-api.server.d.ts.map +1 -0
  208. package/dist/types/index.adminclient.d.ts +27 -0
  209. package/dist/types/index.adminclient.d.ts.map +1 -0
  210. package/dist/types/index.adminserver.d.ts +19 -0
  211. package/dist/types/index.adminserver.d.ts.map +1 -0
  212. package/dist/types/index.d.ts +4 -18
  213. package/dist/types/index.server.d.ts +5 -28
  214. package/dist/types/stories/admin/site-health.stories.d.ts +4 -0
  215. package/dist/types/stories/admin/site-health.stories.d.ts.map +1 -1
  216. package/dist/types/stories/general/sidepanel.stories.d.ts.map +1 -1
  217. package/dist/types/stories/general/smartimage.stories.d.ts +74 -2
  218. package/dist/types/stories/general/smartimage.stories.d.ts.map +1 -1
  219. package/dist/types/tests/site-health-cloudwatch.test.d.ts +2 -0
  220. package/dist/types/tests/site-health-cloudwatch.test.d.ts.map +1 -0
  221. package/dist/types/tests/site-health-on-site-seo.integration.test.d.ts +2 -0
  222. package/dist/types/tests/site-health-on-site-seo.integration.test.d.ts.map +1 -0
  223. package/package.json +20 -10
  224. package/README.COMPONENTS.md +0 -2162
  225. package/dist/components/cms/pixelated.linkedin.js +0 -180
  226. package/dist/components/cms/pixelated.linkedin1.js +0 -84
  227. package/dist/components/cms/pixelated.linkedin2.js +0 -92
  228. package/dist/types/components/cms/pixelated.linkedin.d.ts +0 -2
  229. package/dist/types/components/cms/pixelated.linkedin.d.ts.map +0 -1
  230. package/dist/types/components/cms/pixelated.linkedin1.d.ts +0 -2
  231. package/dist/types/components/cms/pixelated.linkedin1.d.ts.map +0 -1
  232. package/dist/types/components/cms/pixelated.linkedin2.d.ts +0 -2
  233. package/dist/types/components/cms/pixelated.linkedin2.d.ts.map +0 -1
  234. package/dist/types/tests/pixelated.menu-expando.test.d.ts +0 -2
  235. package/dist/types/tests/pixelated.menu-expando.test.d.ts.map +0 -1
@@ -1,6 +1,10 @@
1
1
  'use client';
2
2
  import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
3
+ import PropTypes from 'prop-types';
3
4
  import { SiteHealthTemplate } from './site-health-template';
5
+ SiteHealthUptime.propTypes = {
6
+ siteName: PropTypes.string.isRequired,
7
+ };
4
8
  export function SiteHealthUptime({ siteName }) {
5
9
  const fetchUptimeData = async (site) => {
6
10
  const response = await fetch(`/api/site-health/uptime?siteName=${encodeURIComponent(site)}`);
@@ -89,16 +89,6 @@ CalloutButton.propTypes = {
89
89
  url: PropTypes.string.isRequired,
90
90
  target: PropTypes.string
91
91
  };
92
- /* export function CalloutButton( { title, url, target } : CalloutButtonType) {
93
- return (
94
- <div className="callout-button">
95
- { (url)
96
- ? <button type="button" className="callout-button"><a href={url || ""} target={target || ""} rel={target=="_blank" ? "noopener noreferrer" : ""}>{title}</a></button>
97
- : null
98
- }
99
- </div>
100
- );
101
- } */
102
92
  export function CalloutButton({ title, url, target }) {
103
93
  const handleClick = () => {
104
94
  if (target === '_blank') {
@@ -1,7 +1,7 @@
1
1
  "use client";
2
2
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
3
  import { useState, useEffect, useRef } from 'react';
4
- import PropTypes /* , { InferProps } */ from 'prop-types';
4
+ import PropTypes from 'prop-types';
5
5
  import { SmartImage } from '../cms/smartimage';
6
6
  import { usePixelatedConfig } from '../config/config.client';
7
7
  import { DragHandler } from './carousel.drag';
@@ -11,11 +11,22 @@ function capitalize(str) {
11
11
  }
12
12
  /* ========== CAROUSEL ========== */
13
13
  Carousel.propTypes = {
14
- cards: PropTypes.array.isRequired,
14
+ cards: PropTypes.arrayOf(PropTypes.shape({
15
+ index: PropTypes.number.isRequired,
16
+ cardIndex: PropTypes.number.isRequired,
17
+ cardLength: PropTypes.number.isRequired,
18
+ link: PropTypes.string,
19
+ linkTarget: PropTypes.string,
20
+ image: PropTypes.string.isRequired,
21
+ imageAlt: PropTypes.string,
22
+ imgFit: PropTypes.oneOf(['contain', 'cover', 'fill']),
23
+ headerText: PropTypes.string,
24
+ subHeaderText: PropTypes.string,
25
+ bodyText: PropTypes.string,
26
+ })).isRequired,
15
27
  draggable: PropTypes.bool,
16
28
  imgFit: PropTypes.oneOf(['contain', 'cover', 'fill'])
17
29
  };
18
- // export type CarouselType = InferProps<typeof Carousel.propTypes>;
19
30
  export function Carousel(props) {
20
31
  const debug = false;
21
32
  let timer = useRef(null);
@@ -74,7 +85,7 @@ export function Carousel(props) {
74
85
  console.log('CarouselSimple: Dragging disabled');
75
86
  }
76
87
  if (props.cards && props.cards.length > 0) {
77
- return (_jsxs("div", { className: "carousel-container", children: [_jsx("div", { className: "carousel-cards-container", children: props.cards.map((card, i) => (_jsx(CarouselCard, { index: i, cardIndex: cardIndex, cardLength: props.cards.length, link: card.link, linkTarget: card.linkTarget || '_self', image: card.image, imageAlt: card.imageAlt, imgFit: props.imgFit ? props.imgFit : 'fill', headerText: card.headerText, subHeaderText: card.subHeaderText, bodyText: card.bodyText }, i))) }), _jsxs("div", { className: "carousel-buttons", children: [_jsx(CarouselButton, { clickFunction: previousCard, glyph: '\u25C0' }), _jsx(CarouselButton, { clickFunction: stopTimer, glyph: '\u23F8' }), _jsx(CarouselButton, { clickFunction: nextCard, glyph: '\u25B6' })] })] }));
88
+ return (_jsxs("div", { className: "carousel-container", children: [_jsx("div", { className: "carousel-cards-container", children: props.cards.map((card, i) => (_jsx(CarouselCard, { index: i, cardIndex: cardIndex, cardLength: props.cards.length, link: card.link, linkTarget: card.linkTarget || '_self', image: card.image, imageAlt: card.imageAlt, imgFit: (props.imgFit || 'fill'), headerText: card.headerText, subHeaderText: card.subHeaderText, bodyText: card.bodyText }, i))) }), _jsxs("div", { className: "carousel-buttons", children: [_jsx(CarouselButton, { clickFunction: previousCard, glyph: '\u25C0' }), _jsx(CarouselButton, { clickFunction: stopTimer, glyph: '\u23F8' }), _jsx(CarouselButton, { clickFunction: nextCard, glyph: '\u25B6' })] })] }));
78
89
  }
79
90
  else {
80
91
  return (_jsx("div", { className: 'section-container', children: _jsx("div", { className: "carousel-container", children: _jsx(CarouselLoading, {}) }) }));
@@ -7,7 +7,7 @@ import { usePixelatedConfig } from '../config/config.client';
7
7
  import "../../css/pixelated.grid.scss";
8
8
  import "./tiles.css";
9
9
  Tiles.propTypes = {
10
- cards: PropTypes.object.isRequired,
10
+ cards: PropTypes.array.isRequired,
11
11
  rowCount: PropTypes.number,
12
12
  };
13
13
  export function Tiles(props) {
@@ -5,7 +5,7 @@ import PropTypes from "prop-types";
5
5
  import { Carousel } from '../carousel/carousel';
6
6
  import { getContentfulEntriesByType, getContentfulEntryByEntryID } from "./contentful.delivery";
7
7
  import { usePixelatedConfig } from '../config/config.client';
8
- import { AddToShoppingCart } from "../shoppingcart/shoppingcart.functions";
8
+ import { addToShoppingCart } from "../shoppingcart/shoppingcart.functions";
9
9
  import { AddToCartButton, /* GoToCartButton */ ViewItemDetails } from "../shoppingcart/shoppingcart.components";
10
10
  import { getCloudinaryRemoteFetchURL as getImg } from "./cloudinary";
11
11
  // import { Loading, ToggleLoading } from "../general/pixelated.loading";
@@ -135,7 +135,7 @@ export function ContentfulListItem(props) {
135
135
  ? _jsx(ContentfulItemHeader, { url: itemURL, target: itemURLTarget, title: thisItem.fields.title })
136
136
  : _jsx(ContentfulItemHeader, { title: thisItem.fields.title }) }), _jsxs("div", { className: "contentful-item-details grid12", children: [_jsxs("div", { children: [_jsx("b", { children: "Item ID: " }), thisItem.sys.id] }), _jsxs("div", { children: [_jsx("b", { children: "UPC ID: " }), thisItem.fields.id] }), _jsxs("div", { children: [_jsx("b", { children: "Quantity: " }), thisItem.fields.quantity] }), _jsxs("div", { children: [_jsx("b", { children: "Brand / Model: " }), thisItem.fields.brand, " ", thisItem.fields.model] }), _jsxs("div", { children: [_jsx("b", { children: "Listing Date: " }), thisItem.fields.date] })] }), _jsx("div", { className: "contentful-item-price", children: itemURL
137
137
  ? _jsxs("a", { href: itemURL, target: itemURLTarget, rel: "noreferrer", children: ["$", thisItem.fields.price, " USD"] })
138
- : "$" + thisItem.fields.price + " USD" }), _jsx("br", {}), _jsxs("div", { className: "contentful-item-addtocart", children: [_jsx(ViewItemDetails, { href: "/store", itemID: thisItem.sys.id }), _jsx(AddToCartButton, { handler: AddToShoppingCart, item: shoppingCartItem, itemID: thisItem.sys.id })] })] })] }));
138
+ : "$" + thisItem.fields.price + " USD" }), _jsx("br", {}), _jsxs("div", { className: "contentful-item-addtocart", children: [_jsx(ViewItemDetails, { href: "/store", itemID: thisItem.sys.id }), _jsx(AddToCartButton, { handler: addToShoppingCart, item: shoppingCartItem, itemID: thisItem.sys.id })] })] })] }));
139
139
  }
140
140
  /* ========== CONTENTFUL ITEM HEADER ========== */
141
141
  ContentfulItemHeader.propTypes = {
@@ -156,7 +156,6 @@ ContentfulItemDetail.propTypes = {
156
156
  };
157
157
  export function ContentfulItemDetail(props) {
158
158
  const [item, setItem] = useState({});
159
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
160
159
  const [assets, setAssets] = useState({});
161
160
  const [cards, setCards] = useState([]);
162
161
  const providerContentfulApiProps = usePixelatedConfig()?.contentful;
@@ -235,7 +234,7 @@ export function ContentfulItemDetail(props) {
235
234
  ? _jsx(ContentfulItemHeader, { url: itemURL, title: thisItem.fields.title })
236
235
  : _jsx(ContentfulItemHeader, { title: thisItem.fields.title }) }), _jsx("br", {}), _jsx("div", { className: "contentful-item-photo-carousel grid-s1-e7", children: _jsx(Carousel, { cards: cards, draggable: true, imgFit: "contain" }) }), _jsxs("div", { className: "grid-s7-e13", children: [_jsx("div", { className: "contentful-item-details grid12", children: _jsx("div", { dangerouslySetInnerHTML: { __html: thisItem.fields.description.replace(/(<br\s*\/?>\s*){2,}/gi, '') } }) }), _jsx("br", {}), _jsxs("div", { className: "contentful-item-details grid12", children: [_jsxs("div", { children: [_jsx("b", { children: "Item ID: " }), thisItem.sys.id] }), _jsxs("div", { children: [_jsx("b", { children: "UPC ID: " }), thisItem.fields.id] }), _jsxs("div", { children: [_jsx("b", { children: "Quantity: " }), thisItem.fields.quantity] }), _jsxs("div", { children: [_jsx("b", { children: "Brand / Model: " }), thisItem.fields.brand, " ", thisItem.fields.model] }), _jsxs("div", { children: [_jsx("b", { children: "Listing Date: " }), thisItem.fields.date] }), _jsx("br", {})] }), _jsx("div", { className: "contentful-item-price", children: itemURL
237
236
  ? _jsxs("a", { href: itemURL, target: itemURLTarget, rel: "noreferrer", children: ["$", thisItem.fields.price, " USD"] })
238
- : "$" + thisItem.fields.price + " USD" }), _jsx("br", {}), _jsx("div", { className: "contentful-item-addtocart", children: _jsx(AddToCartButton, { handler: AddToShoppingCart, item: shoppingCartItem, itemID: thisItem.sys.id }) })] })] }) }));
237
+ : "$" + thisItem.fields.price + " USD" }), _jsx("br", {}), _jsx("div", { className: "contentful-item-addtocart", children: _jsx(AddToCartButton, { handler: addToShoppingCart, item: shoppingCartItem, itemID: thisItem.sys.id }) })] })] }) }));
239
238
  }
240
239
  else {
241
240
  return (_jsx(_Fragment, { children: _jsx("div", { id: "contentful-items", className: "contentful-items", children: _jsx("div", { className: "centered", children: "Loading..." }) }) }));
@@ -41,7 +41,7 @@ function getFlickrSize(size) {
41
41
  default: return '';
42
42
  }
43
43
  }
44
- GetFlickrData.PropTypes = {
44
+ GetFlickrData.propTypes = {
45
45
  flickr: PropTypes.object,
46
46
  config: PropTypes.object,
47
47
  };
@@ -22,9 +22,9 @@ export function GoogleReviewsCard(props) {
22
22
  try {
23
23
  const result = await getGoogleReviewsByPlaceId({
24
24
  placeId: props.placeId,
25
- language: props.language,
26
- maxReviews: props.maxReviews,
27
- proxyBase: props.proxyBase,
25
+ language: props.language ?? undefined,
26
+ maxReviews: props.maxReviews ?? undefined,
27
+ proxyBase: props.proxyBase ?? undefined,
28
28
  apiKey: props.apiKey || GOOGLE_MAPS_API_KEY,
29
29
  });
30
30
  setPlace(result.place);
@@ -1,8 +1,18 @@
1
1
  'use client';
2
2
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
3
  import { useState, useEffect } from 'react';
4
+ import PropTypes from 'prop-types';
4
5
  import { getInstagramTiles } from './instagram.functions';
5
6
  import { Tiles } from '../carousel/tiles';
7
+ InstagramTiles.propTypes = {
8
+ accessToken: PropTypes.string,
9
+ userId: PropTypes.string,
10
+ limit: PropTypes.number,
11
+ rowCount: PropTypes.number,
12
+ useThumbnails: PropTypes.bool,
13
+ includeVideos: PropTypes.bool,
14
+ includeCaptions: PropTypes.bool,
15
+ };
6
16
  export function InstagramTiles(props) {
7
17
  const [tiles, setTiles] = useState([]);
8
18
  const [loading, setLoading] = useState(true);
@@ -11,12 +21,12 @@ export function InstagramTiles(props) {
11
21
  (async () => {
12
22
  try {
13
23
  const result = await getInstagramTiles({
14
- accessToken: props.accessToken,
15
- userId: props.userId,
24
+ accessToken: props.accessToken ?? undefined,
25
+ userId: props.userId ?? undefined,
16
26
  limit: props.limit ?? 12,
17
- useThumbnails: props.useThumbnails,
18
- includeVideos: props.includeVideos,
19
- includeCaptions: props.includeCaptions,
27
+ useThumbnails: props.useThumbnails ?? undefined,
28
+ includeVideos: props.includeVideos ?? undefined,
29
+ includeCaptions: props.includeCaptions ?? undefined,
20
30
  });
21
31
  setTiles(result);
22
32
  setLoading(false);
@@ -80,8 +80,8 @@ export function SmartImage(props) {
80
80
  newProps.name = safeString(name);
81
81
  newProps.title = safeString(title);
82
82
  newProps.alt = safeString(alt) ?? '';
83
- newProps.width = parseNumber(width) || 500;
84
- newProps.height = parseNumber(height) || 500;
83
+ newProps.width = parseNumber(width ?? undefined) ?? 500;
84
+ newProps.height = parseNumber(height ?? undefined) ?? 500;
85
85
  const filename = (newProps.src).split('/').pop()?.split('?')[0] || '';
86
86
  const imageName = filename.replace(/\.[^.]+$/, '');
87
87
  newProps.id = newProps.id || newProps.name || sanitizeString(newProps.title) || sanitizeString(newProps.alt) || sanitizeString(imageName);
@@ -1,6 +1,7 @@
1
1
  'use client';
2
2
  import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
3
3
  import { useEffect, useState } from 'react';
4
+ import PropTypes from 'prop-types';
4
5
  import { usePixelatedConfig } from "../config/config.client";
5
6
  import { SmartImage } from './smartimage';
6
7
  import { PageGridItem } from '../general/semantic';
@@ -13,6 +14,13 @@ function decodeString(str) {
13
14
  textarea.innerHTML = str;
14
15
  return textarea.value;
15
16
  }
17
+ BlogPostList.propTypes = {
18
+ site: PropTypes.string,
19
+ baseURL: PropTypes.string,
20
+ count: PropTypes.number,
21
+ posts: PropTypes.array,
22
+ showCategories: PropTypes.bool,
23
+ };
16
24
  export function BlogPostList(props) {
17
25
  const { site: propSite, baseURL: propBaseURL, count, posts: cachedPosts, showCategories = true } = props;
18
26
  const config = usePixelatedConfig();
@@ -34,7 +42,12 @@ export function BlogPostList(props) {
34
42
  // Otherwise, fetch from WordPress
35
43
  ToggleLoading({ show: true });
36
44
  (async () => {
37
- const data = (await getWordPressItems({ site, count, baseURL })) ?? [];
45
+ const params = { site };
46
+ if (count !== null && count !== undefined)
47
+ params.count = count;
48
+ if (baseURL !== null && baseURL !== undefined)
49
+ params.baseURL = baseURL;
50
+ const data = (await getWordPressItems(params)) ?? [];
38
51
  const sorted = data.sort((a, b) => ((a.date ?? '') < (b.date ?? '')) ? 1 : -1);
39
52
  setPosts(sorted);
40
53
  ToggleLoading({ show: false });
@@ -42,20 +55,33 @@ export function BlogPostList(props) {
42
55
  }, [site, baseURL, count, cachedPosts]);
43
56
  return (_jsxs(_Fragment, { children: [_jsx(Loading, {}), posts.map((post) => (_jsx(PageGridItem, { children: _jsx(BlogPostSummary, { ID: post.ID, title: post.title, date: post.date, excerpt: post.excerpt, URL: post.URL, categories: post.categories, featured_image: post.featured_image, showCategories: showCategories }) }, post.ID)))] }));
44
57
  }
58
+ BlogPostSummary.propTypes = {
59
+ ID: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
60
+ title: PropTypes.string,
61
+ date: PropTypes.string,
62
+ excerpt: PropTypes.string,
63
+ URL: PropTypes.string,
64
+ categories: PropTypes.object,
65
+ featured_image: PropTypes.string,
66
+ showCategories: PropTypes.bool,
67
+ };
45
68
  export function BlogPostSummary(props) {
46
- const myCategoryImages = Object.entries(props.categories).map(([category, index]) => [category.trim().toLowerCase().replace(/[ /]+/g, '-'), index]).sort();
69
+ const myCategoryImages = props.categories ? Object.entries(props.categories).map(([category, index]) => [category?.trim().toLowerCase().replace(/[ /]+/g, '-'), index]).sort() : [];
47
70
  const config = usePixelatedConfig();
48
- const myExcerpt = decodeString(props.excerpt).replace(/\[…\]/g, '<a href="' + props.URL + '" target="_blank" rel="noopener noreferrer">[…]</a>');
49
- return (_jsx("div", { className: "blog-post-summary", children: _jsxs("article", { className: "h-entry", children: [_jsx("h2", { className: "p-name", children: _jsx("a", { className: "u-url blog-post-url", href: props.URL, target: "_blank", rel: "noopener noreferrer", children: decodeString(props.title) }) }), _jsxs("div", { className: "dt-published", children: ["Published: ", new Date(props.date).toLocaleDateString()] }), props.featured_image ? (_jsxs("div", { className: "article-body row-12col", children: [_jsx("div", { className: "article-featured-image grid-s1-e4", children: _jsx(SmartImage, { className: "u-photo", src: props.featured_image, alt: decodeString(props.title), title: decodeString(props.title), style: {}, cloudinaryEnv: config?.cloudinary?.product_env ?? undefined, cloudinaryDomain: config?.cloudinary?.baseUrl ?? undefined, cloudinaryTransforms: config?.cloudinary?.transforms ?? undefined }) }), _jsx("div", { className: "article-excerpt grid-s4-e13", children: _jsx("div", { className: "p-summary", dangerouslySetInnerHTML: { __html: myExcerpt } }) })] })) :
71
+ const myExcerpt = props.excerpt ? decodeString(props.excerpt).replace(/\[…\]/g, '<a href="' + (props.URL || '') + '" target="_blank" rel="noopener noreferrer">[…]</a>') : '';
72
+ return (_jsx("div", { className: "blog-post-summary", children: _jsxs("article", { className: "h-entry", children: [_jsx("h2", { className: "p-name", children: _jsx("a", { className: "u-url blog-post-url", href: props.URL || '', target: "_blank", rel: "noopener noreferrer", children: props.title ? decodeString(props.title) : '' }) }), _jsxs("div", { className: "dt-published", children: ["Published: ", props.date ? new Date(props.date).toLocaleDateString() : ''] }), props.featured_image ? (_jsxs("div", { className: "article-body row-12col", children: [_jsx("div", { className: "article-featured-image grid-s1-e4", children: _jsx(SmartImage, { className: "u-photo", src: props.featured_image, alt: props.title ? decodeString(props.title) : '', title: props.title ? decodeString(props.title) : '', style: {}, cloudinaryEnv: config?.cloudinary?.product_env ?? undefined, cloudinaryDomain: config?.cloudinary?.baseUrl ?? undefined, cloudinaryTransforms: config?.cloudinary?.transforms ?? undefined }) }), _jsx("div", { className: "article-excerpt grid-s4-e13", children: _jsx("div", { className: "p-summary", dangerouslySetInnerHTML: { __html: myExcerpt } }) })] })) :
50
73
  _jsx("div", { className: "article-excerpt grid-s1-e13", children: _jsx("div", { className: "p-summary", dangerouslySetInnerHTML: { __html: myExcerpt } }) }), props.showCategories !== false && (_jsxs("div", { children: ["Categories:", myCategoryImages.map(([categoryImg, index]) => (_jsx("span", { className: "p-category", children: _jsx(SmartImage, { src: `/images/icons/${categoryImg}.png`, title: String(categoryImg), alt: String(categoryImg), cloudinaryEnv: config?.cloudinary?.product_env ?? undefined, cloudinaryDomain: config?.cloudinary?.baseUrl ?? undefined, cloudinaryTransforms: config?.cloudinary?.transforms ?? undefined }) }, categoryImg + "-" + index)))] }))] }) }, props.ID));
51
74
  }
75
+ BlogPostCategories.propTypes = {
76
+ categories: PropTypes.arrayOf(PropTypes.string),
77
+ };
52
78
  export function BlogPostCategories(props) {
53
79
  if (!props.categories || props.categories.length === 0) {
54
80
  return null;
55
81
  }
56
- const myCategoryImages = props.categories.map((category) => (category !== "Uncategorized")
82
+ const myCategoryImages = props.categories.map((category) => (category && category !== "Uncategorized")
57
83
  ? category.trim().toLowerCase().replace(/[ /]+/g, '-')
58
- : undefined).sort();
84
+ : undefined).filter(Boolean).sort();
59
85
  const config = usePixelatedConfig();
60
86
  return (_jsxs("div", { className: "blogPostCategories", children: [_jsx("div", { children: "Categories: " }), myCategoryImages.map((categoryImg, index) => categoryImg ? (_jsx("span", { className: "p-category", children: _jsx(SmartImage, { className: "u-photo", src: `/images/icons/${categoryImg}.png`, title: String(categoryImg), alt: String(categoryImg), cloudinaryEnv: config?.cloudinary?.product_env ?? undefined, cloudinaryDomain: config?.cloudinary?.baseUrl ?? undefined, cloudinaryTransforms: config?.cloudinary?.transforms ?? undefined }) }, categoryImg + "-" + index)) : null)] }));
61
87
  }
@@ -1,6 +1,7 @@
1
1
  "use client";
2
2
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
3
  import { useState, useEffect } from "react";
4
+ import PropTypes from 'prop-types';
4
5
  /*
5
6
  NOTE : development has stopped for this component
6
7
  as Yelp Base API Access costs $229 per month.
@@ -12,6 +13,10 @@ https://www.google.com/search?q=yelp+reviews+react+component&oq=yelp+reviews+rea
12
13
  https://www.reddit.com/r/nextjs/comments/16smhqa/next_js_fetching_data_from_yelp_api/
13
14
  https://helloputnam.medium.com/easiest-way-to-include-business-reviews-on-a-web-app-google-facebook-yelp-etc-de3e243bbe75
14
15
  */
16
+ YelpReviews.propTypes = {
17
+ businessID: PropTypes.string.isRequired,
18
+ key: PropTypes.string,
19
+ };
15
20
  export function YelpReviews(props) {
16
21
  const [reviews, setReviews] = useState([]);
17
22
  const [loading, setLoading] = useState(true);
@@ -1,9 +1,15 @@
1
1
  import { jsx as _jsx } from "react/jsx-runtime";
2
+ import PropTypes from 'prop-types';
2
3
  import { getClientOnlyPixelatedConfig } from './config';
3
4
  // Server wrapper: reads server env blob and sanitizes it, then mounts the client provider.
4
5
  // Important: do NOT import client components at module scope — dynamically import
5
6
  // the client provider inside the function so this module remains server-safe.
6
- export async function PixelatedServerConfigProvider({ config, children, }) {
7
+ PixelatedServerConfigProvider.propTypes = {
8
+ config: PropTypes.object,
9
+ children: PropTypes.node.isRequired,
10
+ };
11
+ export async function PixelatedServerConfigProvider(props) {
12
+ const { config, children } = props;
7
13
  const cfg = config ?? getClientOnlyPixelatedConfig();
8
14
  const mod = await import('./config.client');
9
15
  const Provider = mod.PixelatedClientConfigProvider;
@@ -1,4 +1,3 @@
1
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
2
1
  function isPartialMatchInArray(searchString, array) {
3
2
  // Convert both the search string and array items to lowercase for case-insensitive matching
4
3
  const lowerCaseSearchString = searchString.toLowerCase();
@@ -20,7 +20,6 @@
20
20
  imageObserver.observe(image);
21
21
  });
22
22
  } */
23
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
24
23
  function isInViewport(el) {
25
24
  const rect = el.getBoundingClientRect();
26
25
  return (rect.top >= 0 &&
@@ -7,7 +7,8 @@ https://signalvnoise.com/posts/2577-loading-spinner-animation-using-css-and-webk
7
7
  https://www.andreaverlicchi.eu/blog/css-3-only-spinning-loading-animation/
8
8
  */
9
9
  /* ========== MARKDOWN ========== */
10
- export function Loading() {
10
+ Loading.propTypes = {};
11
+ export function Loading(props) {
11
12
  return (_jsx(_Fragment, { children: _jsx("div", { id: "loadingSpinner", className: "loading", children: _jsxs("div", { className: "spinner", children: [_jsx("div", { className: "bar1" }), _jsx("div", { className: "bar2" }), _jsx("div", { className: "bar3" }), _jsx("div", { className: "bar4" }), _jsx("div", { className: "bar5" }), _jsx("div", { className: "bar6" }), _jsx("div", { className: "bar7" }), _jsx("div", { className: "bar8" }), _jsx("div", { className: "bar9" }), _jsx("div", { className: "bar10" }), _jsx("div", { className: "bar11" }), _jsx("div", { className: "bar12" })] }) }) }));
12
13
  }
13
14
  ToggleLoading.propTypes = {
@@ -29,7 +29,6 @@ export function MicroInteractions(props) {
29
29
  if (props.scrollfadeElements)
30
30
  ScrollFade(props.scrollfadeElements);
31
31
  }
32
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
33
32
  function isElementInViewport(el) {
34
33
  const rect = el.getBoundingClientRect();
35
34
  return (rect.top >= 0 &&
@@ -1,11 +1,9 @@
1
1
 
2
2
  .modal {
3
-
4
3
  position: fixed; /* Stay in place */
5
4
  z-index: 1000; /* Sit on top */
6
- top: 50%;
7
- left: 50%;
8
- transform: translate(-50%, -50%);
5
+ top: 0;
6
+ left: 0;
9
7
  width: 100%; /* Full width */
10
8
  height: 100%; /* Full height */
11
9
  overflow: auto; /* Enable scroll if needed */
@@ -1,45 +1,87 @@
1
1
  "use client";
2
2
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
- import { useEffect } from 'react';
3
+ import { useEffect, useRef } from 'react';
4
+ import PropTypes from 'prop-types';
4
5
  import './modal.css';
5
6
  /*
6
7
  https://www.w3schools.com/howto/howto_css_modals.asp
7
8
  */
8
- export function Modal(props) {
9
- const myModalID = "myModal" + (props.modalID ?? '');
10
- const myModalCloseID = "myModalClose" + (props.modalID ?? '');
9
+ Modal.propTypes = {
10
+ modalContent: PropTypes.node.isRequired,
11
+ modalID: PropTypes.string,
12
+ isOpen: PropTypes.bool,
13
+ handleCloseEvent: PropTypes.func,
14
+ };
15
+ export function Modal({ modalContent, modalID, isOpen = false, handleCloseEvent }) {
16
+ const myModalID = "myModal" + (modalID ?? '');
17
+ const myModalCloseID = "myModalClose" + (modalID ?? '');
18
+ const modalRef = useRef(null);
11
19
  useEffect(() => {
12
- const handleModalClose = (event) => {
13
- event.preventDefault();
14
- const myModal = document.getElementById(myModalID);
15
- if (myModal) {
16
- myModal.style.display = 'none';
17
- }
18
- };
19
- const myModalClose = document.getElementById(myModalCloseID);
20
- if (myModalClose) {
21
- myModalClose.addEventListener('click', handleModalClose);
22
- }
23
- ;
24
- const handleWindowOnClick = (event) => {
25
- const myModal = document.getElementById(myModalID);
26
- if (event.target == myModal) {
20
+ // Only use DOM event listeners for backward compatibility when handleCloseEvent is not provided
21
+ if (!handleCloseEvent) {
22
+ const handleModalClose = (event) => {
23
+ event.preventDefault();
24
+ const myModal = document.getElementById(myModalID);
27
25
  if (myModal) {
28
- myModal.style.display = "none";
26
+ myModal.style.display = 'none';
29
27
  }
30
- ;
31
- }
32
- };
33
- window.addEventListener('click', handleWindowOnClick);
34
- return () => {
35
- window.removeEventListener('click', handleWindowOnClick);
28
+ };
29
+ const myModalClose = document.getElementById(myModalCloseID);
36
30
  if (myModalClose) {
37
- myModalClose.removeEventListener('click', handleModalClose);
31
+ myModalClose.addEventListener('click', handleModalClose);
38
32
  }
39
33
  ;
40
- };
41
- }, []);
42
- return (_jsx("div", { id: myModalID, className: "modal", style: { display: 'none' }, children: _jsxs("div", { className: "modal-content", children: [_jsx("span", { id: myModalCloseID, className: "modal-close", "aria-hidden": "true", children: "\u00D7" }), props.modalContent] }) }));
34
+ const handleWindowOnClick = (event) => {
35
+ const myModal = document.getElementById(myModalID);
36
+ if (event.target == myModal) {
37
+ if (myModal) {
38
+ myModal.style.display = 'none';
39
+ }
40
+ }
41
+ };
42
+ window.addEventListener('click', handleWindowOnClick);
43
+ return () => {
44
+ window.removeEventListener('click', handleWindowOnClick);
45
+ if (myModalClose) {
46
+ myModalClose.removeEventListener('click', handleModalClose);
47
+ }
48
+ ;
49
+ };
50
+ }
51
+ else {
52
+ // For React approach, add escape key listener
53
+ const handleEscape = (event) => {
54
+ if (event.key === 'Escape') {
55
+ handleCloseEvent();
56
+ }
57
+ };
58
+ document.addEventListener('keydown', handleEscape);
59
+ return () => {
60
+ document.removeEventListener('keydown', handleEscape);
61
+ };
62
+ }
63
+ }, [myModalID, myModalCloseID, handleCloseEvent]);
64
+ const handleCloseClick = handleCloseEvent ? (event) => {
65
+ event.preventDefault();
66
+ handleCloseEvent();
67
+ } : undefined;
68
+ const handleCloseKeyDown = handleCloseEvent ? (event) => {
69
+ if (event.key === 'Enter' || event.key === ' ') {
70
+ event.preventDefault();
71
+ handleCloseEvent();
72
+ }
73
+ } : undefined;
74
+ const handleModalClick = handleCloseEvent ? (event) => {
75
+ if (event.target === modalRef.current) {
76
+ handleCloseEvent();
77
+ }
78
+ } : undefined;
79
+ const handleModalKeyDown = handleCloseEvent ? (event) => {
80
+ if (event.key === 'Escape' && event.target === modalRef.current) {
81
+ handleCloseEvent();
82
+ }
83
+ } : undefined;
84
+ return (_jsx("div", { id: myModalID, className: "modal", style: { display: isOpen ? 'block' : 'none' }, ref: modalRef, onClick: handleModalClick, children: _jsxs("div", { className: "modal-content", role: "dialog", "aria-modal": "true", children: [_jsx("button", { id: myModalCloseID, className: "modal-close", "aria-label": "Close modal", onClick: handleCloseClick, onKeyDown: handleCloseKeyDown, type: "button", children: "\u00D7" }), modalContent] }) }));
43
85
  }
44
86
  export const handleModalOpen = (event, modalID) => {
45
87
  const myModalID = "myModal" + (modalID ?? '');
@@ -3,7 +3,23 @@
3
3
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
4
4
  import { useEffect, useRef, useState } from 'react';
5
5
  import { createPortal } from 'react-dom';
6
+ import PropTypes from 'prop-types';
6
7
  import './sidepanel.css';
8
+ // Define const arrays for options - used by both PropTypes and form generation
9
+ export const positions = ['left', 'right'];
10
+ SidePanel.propTypes = {
11
+ isOpen: PropTypes.bool.isRequired,
12
+ onClose: PropTypes.func.isRequired,
13
+ onToggle: PropTypes.func,
14
+ position: PropTypes.oneOf([...positions]),
15
+ width: PropTypes.string,
16
+ showOverlay: PropTypes.bool,
17
+ showTab: PropTypes.bool,
18
+ tabIcon: PropTypes.node,
19
+ tabLabel: PropTypes.string,
20
+ children: PropTypes.node,
21
+ className: PropTypes.string,
22
+ };
7
23
  export default function SidePanel({ isOpen, onClose, onToggle, position = 'left', width = '300px', showOverlay = true, showTab = false, tabIcon /* = "≡" */, tabLabel, children, className = '' }) {
8
24
  const portalRootRef = useRef(null);
9
25
  const wrapperRef = useRef(null);
@@ -1,3 +1,4 @@
1
+ "use client";
1
2
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
3
  import { useState } from 'react';
3
4
  import PropTypes from 'prop-types';
@@ -26,7 +26,7 @@
26
26
  .panelMenuButton .hamburger{
27
27
  cursor: pointer;
28
28
  font-family: Verdana;
29
- font-size: 1.5rem;
29
+ font-size: 1.75rem;
30
30
  color: #CCC;
31
31
 
32
32
  }
@@ -4,6 +4,15 @@ import { useEffect, useRef } from 'react';
4
4
  import PropTypes from 'prop-types';
5
5
  import './menu-accordion.css';
6
6
  const hamburgerIcon = "≡"; /* (U+2261) */ /* ||| */
7
+ const menuItemShape = PropTypes.shape({
8
+ name: PropTypes.string.isRequired,
9
+ path: PropTypes.string,
10
+ target: PropTypes.string,
11
+ routes: PropTypes.array, // Will be refined after function declaration
12
+ hidden: PropTypes.bool,
13
+ });
14
+ // Update the recursive reference after the shape is defined
15
+ menuItemShape.routes = PropTypes.arrayOf(menuItemShape);
7
16
  function generateMenuItems({ menuData, state = "hide" }) {
8
17
  const myItems = [];
9
18
  let index = 0;
@@ -27,9 +36,8 @@ function generateMenuItems({ menuData, state = "hide" }) {
27
36
  }
28
37
  return myItems;
29
38
  }
30
- /* ========== MENU ========== */
31
39
  MenuAccordion.propTypes = {
32
- menuItems: PropTypes.any.isRequired,
40
+ menuItems: PropTypes.arrayOf(menuItemShape).isRequired,
33
41
  showHidden: PropTypes.bool,
34
42
  };
35
43
  export function MenuAccordion(props) {
@@ -145,7 +153,10 @@ export function MenuAccordion(props) {
145
153
  }
146
154
  /* ========== MENU GROUP ========== */
147
155
  MenuAccordionGroup.propTypes = {
148
- menuItems: PropTypes.object.isRequired,
156
+ menuItems: PropTypes.oneOfType([
157
+ menuItemShape,
158
+ PropTypes.arrayOf(menuItemShape)
159
+ ]).isRequired,
149
160
  state: PropTypes.string,
150
161
  };
151
162
  export function MenuAccordionGroup(props) {
@@ -168,7 +179,7 @@ export function MenuAccordionItem(props) {
168
179
  https://www.unclebigbay.com/blog/building-the-world-simplest-hamburger-with-html-and-css
169
180
  */
170
181
  MenuAccordionButton.propTypes = {};
171
- export function MenuAccordionButton() {
182
+ export function MenuAccordionButton(props) {
172
183
  function slideMobilePanel() {
173
184
  if (typeof window !== 'undefined' && window.moveMenu) {
174
185
  window.moveMenu();