@universityofmaryland/web-feeds-library 1.3.0-beta.2 → 1.3.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 (88) hide show
  1. package/dist/experts.js +2 -0
  2. package/dist/experts.js.map +1 -1
  3. package/dist/factory/core/createBaseFeed.d.ts.map +1 -1
  4. package/dist/factory/core/createBaseFeed.js +2 -0
  5. package/dist/factory/core/createBaseFeed.js.map +1 -1
  6. package/dist/factory/core/types.d.ts +1 -0
  7. package/dist/factory/core/types.d.ts.map +1 -1
  8. package/dist/feeds/events/grid.js +1 -0
  9. package/dist/feeds/events/grid.js.map +1 -1
  10. package/dist/feeds/events/grouped.js +1 -0
  11. package/dist/feeds/events/grouped.js.map +1 -1
  12. package/dist/feeds/events/list.js +1 -0
  13. package/dist/feeds/events/list.js.map +1 -1
  14. package/dist/feeds/experts/_types.d.ts +8 -2
  15. package/dist/feeds/experts/_types.d.ts.map +1 -1
  16. package/dist/feeds/experts/bio.d.ts.map +1 -1
  17. package/dist/feeds/experts/bio.js +14 -4
  18. package/dist/feeds/experts/bio.js.map +1 -1
  19. package/dist/feeds/experts/grid.js +1 -0
  20. package/dist/feeds/experts/grid.js.map +1 -1
  21. package/dist/feeds/experts/in-the-news.d.ts +4 -0
  22. package/dist/feeds/experts/in-the-news.d.ts.map +1 -0
  23. package/dist/feeds/experts/in-the-news.js +348 -0
  24. package/dist/feeds/experts/in-the-news.js.map +1 -0
  25. package/dist/feeds/experts/index.d.ts +1 -0
  26. package/dist/feeds/experts/index.d.ts.map +1 -1
  27. package/dist/feeds/experts/list.js +1 -0
  28. package/dist/feeds/experts/list.js.map +1 -1
  29. package/dist/feeds/in-the-news/_types.d.ts +14 -0
  30. package/dist/feeds/in-the-news/_types.d.ts.map +1 -0
  31. package/dist/feeds/in-the-news/grid.d.ts +4 -0
  32. package/dist/feeds/in-the-news/grid.d.ts.map +1 -0
  33. package/dist/feeds/in-the-news/grid.js +28 -0
  34. package/dist/feeds/in-the-news/grid.js.map +1 -0
  35. package/dist/feeds/in-the-news/index.d.ts +3 -0
  36. package/dist/feeds/in-the-news/index.d.ts.map +1 -0
  37. package/dist/feeds/in-the-news/list.d.ts +4 -0
  38. package/dist/feeds/in-the-news/list.d.ts.map +1 -0
  39. package/dist/feeds/in-the-news/list.js +29 -0
  40. package/dist/feeds/in-the-news/list.js.map +1 -0
  41. package/dist/feeds/news/featured.d.ts.map +1 -1
  42. package/dist/feeds/news/featured.js +10 -3
  43. package/dist/feeds/news/featured.js.map +1 -1
  44. package/dist/feeds/news/grid.js +1 -0
  45. package/dist/feeds/news/grid.js.map +1 -1
  46. package/dist/feeds/news/list.js +1 -0
  47. package/dist/feeds/news/list.js.map +1 -1
  48. package/dist/in-the-news.d.ts +2 -0
  49. package/dist/in-the-news.js +7 -0
  50. package/dist/in-the-news.js.map +1 -0
  51. package/dist/index.d.ts +1 -0
  52. package/dist/index.d.ts.map +1 -1
  53. package/dist/index.js +2 -0
  54. package/dist/index.js.map +1 -1
  55. package/dist/strategies/display/experts.d.ts +2 -1
  56. package/dist/strategies/display/experts.d.ts.map +1 -1
  57. package/dist/strategies/display/experts.js +43 -11
  58. package/dist/strategies/display/experts.js.map +1 -1
  59. package/dist/strategies/display/inTheNews.d.ts +4 -0
  60. package/dist/strategies/display/inTheNews.d.ts.map +1 -0
  61. package/dist/strategies/display/inTheNews.js +99 -0
  62. package/dist/strategies/display/inTheNews.js.map +1 -0
  63. package/dist/strategies/display/index.d.ts +2 -1
  64. package/dist/strategies/display/index.d.ts.map +1 -1
  65. package/dist/strategies/fetch/experts.d.ts +1 -1
  66. package/dist/strategies/fetch/experts.d.ts.map +1 -1
  67. package/dist/strategies/fetch/experts.js +11 -8
  68. package/dist/strategies/fetch/experts.js.map +1 -1
  69. package/dist/strategies/fetch/graphql.d.ts.map +1 -1
  70. package/dist/strategies/fetch/graphql.js +6 -3
  71. package/dist/strategies/fetch/graphql.js.map +1 -1
  72. package/dist/strategies/fetch/inTheNews.d.ts +4 -0
  73. package/dist/strategies/fetch/inTheNews.d.ts.map +1 -0
  74. package/dist/strategies/fetch/inTheNews.js +87 -0
  75. package/dist/strategies/fetch/inTheNews.js.map +1 -0
  76. package/dist/strategies/fetch/index.d.ts +2 -0
  77. package/dist/strategies/fetch/index.d.ts.map +1 -1
  78. package/dist/strategies/index.d.ts +3 -3
  79. package/dist/strategies/index.d.ts.map +1 -1
  80. package/dist/types/api.d.ts +1 -0
  81. package/dist/types/api.d.ts.map +1 -1
  82. package/dist/types/data/experts.d.ts +8 -0
  83. package/dist/types/data/experts.d.ts.map +1 -1
  84. package/dist/types/data/inTheNews.d.ts +32 -0
  85. package/dist/types/data/inTheNews.d.ts.map +1 -0
  86. package/dist/types/data/index.d.ts +1 -0
  87. package/dist/types/data/index.d.ts.map +1 -1
  88. package/package.json +6 -1
package/dist/experts.js CHANGED
@@ -1,9 +1,11 @@
1
1
  import { expertsGrid } from "./feeds/experts/grid.js";
2
2
  import { expertsList } from "./feeds/experts/list.js";
3
3
  import { expertsBio } from "./feeds/experts/bio.js";
4
+ import { expertsInTheNews } from "./feeds/experts/in-the-news.js";
4
5
  export {
5
6
  expertsBio as bio,
6
7
  expertsGrid as grid,
8
+ expertsInTheNews as inTheNews,
7
9
  expertsList as list
8
10
  };
9
11
  //# sourceMappingURL=experts.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"experts.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;"}
1
+ {"version":3,"file":"experts.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;"}
@@ -1 +1 @@
1
- {"version":3,"file":"createBaseFeed.d.ts","sourceRoot":"","sources":["../../../source/factory/core/createBaseFeed.ts"],"names":[],"mappings":"AAeA,OAAO,EAAE,cAAc,EAAE,iBAAiB,EAAsB,MAAM,SAAS,CAAC;AAyChF,wBAAgB,cAAc,CAAC,KAAK,EAAE,UAAU,GAAG,GAAG,EACpD,MAAM,EAAE,cAAc,CAAC,KAAK,EAAE,UAAU,CAAC,GACxC,iBAAiB,CAoInB"}
1
+ {"version":3,"file":"createBaseFeed.d.ts","sourceRoot":"","sources":["../../../source/factory/core/createBaseFeed.ts"],"names":[],"mappings":"AAeA,OAAO,EAAE,cAAc,EAAE,iBAAiB,EAAsB,MAAM,SAAS,CAAC;AAyChF,wBAAgB,cAAc,CAAC,KAAK,EAAE,UAAU,GAAG,GAAG,EACpD,MAAM,EAAE,cAAc,CAAC,KAAK,EAAE,UAAU,CAAC,GACxC,iBAAiB,CAsInB"}
@@ -20,6 +20,7 @@ function createBaseFeed(config) {
20
20
  isLazyLoad = false,
21
21
  enableCategoryFallback = false,
22
22
  categories,
23
+ ids,
23
24
  entriesToRemove,
24
25
  fetchStrategy,
25
26
  displayStrategy,
@@ -58,6 +59,7 @@ function createBaseFeed(config) {
58
59
  const baseProps = {
59
60
  token,
60
61
  categories,
62
+ ids,
61
63
  entriesToRemove,
62
64
  numberOfColumnsToShow,
63
65
  numberOfRowsToStart,
@@ -1 +1 @@
1
- {"version":3,"file":"createBaseFeed.js","sources":["../../../source/factory/core/createBaseFeed.ts"],"sourcesContent":["/**\n * Base Feed Factory\n *\n * Creates a complete feed with initialization, data fetching, and display logic.\n * Uses strategy pattern to allow customization of fetch, display, and layout.\n *\n * @module factory/core/createBaseFeed\n */\n\nimport { LoadingState } from '../../states';\nimport {\n createFeedHelpers,\n createDisplayHandlers,\n createFetchHandlers,\n} from '../helpers';\nimport { BaseFeedConfig, FeedFactoryResult, CardMappingOptions } from './types';\n\n/**\n * Create a base feed using the factory pattern\n *\n * This factory eliminates ~70% of boilerplate code by handling:\n * - Feed initialization (container, loading, state)\n * - Strategy composition (fetch, display, layout)\n * - Lifecycle management (start, load more, no results)\n * - Shadow DOM support\n * - Event system\n *\n * @template TData - The type of entry data from the API\n * @template TVariables - The type of API variables\n *\n * @param config - Configuration for the feed\n * @returns ElementModel with feed element and styles\n *\n * @example\n * ```typescript\n * // Simple grid feed\n * const eventsFeed = createBaseFeed({\n * token: 'my-token',\n * isThemeDark: false,\n * numberOfColumnsToShow: 3,\n * numberOfRowsToStart: 2,\n * isLazyLoad: true,\n * fetchStrategy: eventsFetchStrategy,\n * displayStrategy: eventsDisplayStrategy,\n * layoutStrategy: gridGapLayout,\n * imageConfig: (entry) => ({\n * imageUrl: entry.image[0].url,\n * altText: entry.image[0].altText,\n * linkUrl: entry.url,\n * }),\n * });\n *\n * // Use the feed\n * document.body.appendChild(eventsFeed.element);\n * ```\n */\nexport function createBaseFeed<TData, TVariables = any>(\n config: BaseFeedConfig<TData, TVariables>,\n): FeedFactoryResult {\n const {\n token,\n isThemeDark = false,\n isTransparent = false,\n isOverlay = false,\n isAligned = false,\n isMediaTrained = null,\n cardType,\n numberOfColumnsToShow = 1,\n numberOfRowsToStart,\n isLazyLoad = false,\n enableCategoryFallback = false,\n categories,\n entriesToRemove,\n fetchStrategy,\n displayStrategy,\n layoutStrategy,\n noResultsConfig,\n imageConfig,\n } = config;\n\n const container = document.createElement('div');\n const loading = new LoadingState({ isThemeDark });\n let styles = loading.styles;\n\n // Create helpers for state management\n const helpers = createFeedHelpers({\n container,\n initialStyles: styles,\n });\n\n // Override setStyles to also update the local styles variable\n const originalSetStyles = helpers.setStyles;\n helpers.setStyles = (additionalStyles: string) => {\n styles += additionalStyles;\n originalSetStyles(additionalStyles);\n };\n\n // Shadow root support\n let shadowRoot: ShadowRoot | null = null;\n const shadowRootCallback = (shadow: ShadowRoot) => {\n shadowRoot = shadow;\n\n helpers.setShadowRoot(shadow);\n };\n\n const cardMappingOptions: CardMappingOptions = {\n isThemeDark,\n isTransparent,\n isOverlay,\n isAligned,\n imageConfig,\n ...(cardType && { cardType }),\n };\n\n const layoutElement = layoutStrategy.create({\n columns: numberOfColumnsToShow as 2 | 3 | 4,\n isThemeDark,\n });\n helpers.setStyles(layoutElement.styles);\n\n const baseProps = {\n token,\n categories,\n entriesToRemove,\n numberOfColumnsToShow,\n numberOfRowsToStart,\n isLazyLoad,\n isMediaTrained,\n getOffset: helpers.getOffset,\n };\n\n // Create a mutable reference for lazy load callback\n // This allows us to set it after fetchHandlers are created\n const lazyLoadCallbackRef = {\n current: undefined as (() => Promise<void>) | undefined,\n };\n\n // Create display handlers with callback reference\n const displayHandlers = createDisplayHandlers({\n displayStrategy,\n layoutStrategy,\n helpers,\n cardMappingOptions,\n isLazyLoad,\n numberOfColumnsToShow,\n numberOfRowsToStart,\n noResultsConfig: {\n ...noResultsConfig,\n isThemeDark, // Ensure theme is passed to EmptyState\n },\n // Pass a function that calls the current callback\n lazyLoadCallback: isLazyLoad\n ? async () => {\n if (lazyLoadCallbackRef.current) {\n await lazyLoadCallbackRef.current();\n }\n }\n : undefined,\n });\n\n // Create fetch handlers\n const fetchHandlers = createFetchHandlers({\n fetchStrategy,\n helpers,\n baseProps,\n displayHandlers,\n layoutElement,\n isThemeDark,\n enableCategoryFallback,\n });\n\n // Set the lazy load callback reference now that fetch handlers exist\n lazyLoadCallbackRef.current = fetchHandlers.loadMore;\n\n // Append loading indicator to container\n container.appendChild(loading.element);\n\n // Start fetching data\n fetchHandlers.start();\n\n // Return feed with getter for styles to ensure dynamic access\n return {\n element: container,\n get styles() {\n return styles;\n },\n events: {\n callback: shadowRootCallback,\n },\n };\n}\n"],"names":[],"mappings":";;;;;;;;AAwDO,SAAS,eACd,QACmB;AACnB,QAAM;AAAA,IACJ;AAAA,IACA,cAAc;AAAA,IACd,gBAAgB;AAAA,IAChB,YAAY;AAAA,IACZ,YAAY;AAAA,IACZ,iBAAiB;AAAA,IACjB;AAAA,IACA,wBAAwB;AAAA,IACxB;AAAA,IACA,aAAa;AAAA,IACb,yBAAyB;AAAA,IACzB;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EAAA,IACE;AAEJ,QAAM,YAAY,SAAS,cAAc,KAAK;AAC9C,QAAM,UAAU,IAAI,aAAa,EAAE,aAAa;AAChD,MAAI,SAAS,QAAQ;AAGrB,QAAM,UAAU,kBAAkB;AAAA,IAChC;AAAA,IACA,eAAe;AAAA,EAAA,CAChB;AAGD,QAAM,oBAAoB,QAAQ;AAClC,UAAQ,YAAY,CAAC,qBAA6B;AAChD,cAAU;AACV,sBAAkB,gBAAgB;AAAA,EACpC;AAIA,QAAM,qBAAqB,CAAC,WAAuB;AAGjD,YAAQ,cAAc,MAAM;AAAA,EAC9B;AAEA,QAAM,qBAAyC;AAAA,IAC7C;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA,GAAI,YAAY,EAAE,SAAA;AAAA,EAAS;AAG7B,QAAM,gBAAgB,eAAe,OAAO;AAAA,IAC1C,SAAS;AAAA,IACT;AAAA,EAAA,CACD;AACD,UAAQ,UAAU,cAAc,MAAM;AAEtC,QAAM,YAAY;AAAA,IAChB;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA,WAAW,QAAQ;AAAA,EAAA;AAKrB,QAAM,sBAAsB;AAAA,IAC1B,SAAS;AAAA,EAAA;AAIX,QAAM,kBAAkB,sBAAsB;AAAA,IAC5C;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA,iBAAiB;AAAA,MACf,GAAG;AAAA,MACH;AAAA;AAAA,IAAA;AAAA;AAAA,IAGF,kBAAkB,aACd,YAAY;AACV,UAAI,oBAAoB,SAAS;AAC/B,cAAM,oBAAoB,QAAA;AAAA,MAC5B;AAAA,IACF,IACA;AAAA,EAAA,CACL;AAGD,QAAM,gBAAgB,oBAAoB;AAAA,IACxC;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EAAA,CACD;AAGD,sBAAoB,UAAU,cAAc;AAG5C,YAAU,YAAY,QAAQ,OAAO;AAGrC,gBAAc,MAAA;AAGd,SAAO;AAAA,IACL,SAAS;AAAA,IACT,IAAI,SAAS;AACX,aAAO;AAAA,IACT;AAAA,IACA,QAAQ;AAAA,MACN,UAAU;AAAA,IAAA;AAAA,EACZ;AAEJ;"}
1
+ {"version":3,"file":"createBaseFeed.js","sources":["../../../source/factory/core/createBaseFeed.ts"],"sourcesContent":["/**\n * Base Feed Factory\n *\n * Creates a complete feed with initialization, data fetching, and display logic.\n * Uses strategy pattern to allow customization of fetch, display, and layout.\n *\n * @module factory/core/createBaseFeed\n */\n\nimport { LoadingState } from '../../states';\nimport {\n createFeedHelpers,\n createDisplayHandlers,\n createFetchHandlers,\n} from '../helpers';\nimport { BaseFeedConfig, FeedFactoryResult, CardMappingOptions } from './types';\n\n/**\n * Create a base feed using the factory pattern\n *\n * This factory eliminates ~70% of boilerplate code by handling:\n * - Feed initialization (container, loading, state)\n * - Strategy composition (fetch, display, layout)\n * - Lifecycle management (start, load more, no results)\n * - Shadow DOM support\n * - Event system\n *\n * @template TData - The type of entry data from the API\n * @template TVariables - The type of API variables\n *\n * @param config - Configuration for the feed\n * @returns ElementModel with feed element and styles\n *\n * @example\n * ```typescript\n * // Simple grid feed\n * const eventsFeed = createBaseFeed({\n * token: 'my-token',\n * isThemeDark: false,\n * numberOfColumnsToShow: 3,\n * numberOfRowsToStart: 2,\n * isLazyLoad: true,\n * fetchStrategy: eventsFetchStrategy,\n * displayStrategy: eventsDisplayStrategy,\n * layoutStrategy: gridGapLayout,\n * imageConfig: (entry) => ({\n * imageUrl: entry.image[0].url,\n * altText: entry.image[0].altText,\n * linkUrl: entry.url,\n * }),\n * });\n *\n * // Use the feed\n * document.body.appendChild(eventsFeed.element);\n * ```\n */\nexport function createBaseFeed<TData, TVariables = any>(\n config: BaseFeedConfig<TData, TVariables>,\n): FeedFactoryResult {\n const {\n token,\n isThemeDark = false,\n isTransparent = false,\n isOverlay = false,\n isAligned = false,\n isMediaTrained = null,\n cardType,\n numberOfColumnsToShow = 1,\n numberOfRowsToStart,\n isLazyLoad = false,\n enableCategoryFallback = false,\n categories,\n ids,\n entriesToRemove,\n fetchStrategy,\n displayStrategy,\n layoutStrategy,\n noResultsConfig,\n imageConfig,\n } = config;\n\n const container = document.createElement('div');\n const loading = new LoadingState({ isThemeDark });\n let styles = loading.styles;\n\n // Create helpers for state management\n const helpers = createFeedHelpers({\n container,\n initialStyles: styles,\n });\n\n // Override setStyles to also update the local styles variable\n const originalSetStyles = helpers.setStyles;\n helpers.setStyles = (additionalStyles: string) => {\n styles += additionalStyles;\n originalSetStyles(additionalStyles);\n };\n\n // Shadow root support\n let shadowRoot: ShadowRoot | null = null;\n const shadowRootCallback = (shadow: ShadowRoot) => {\n shadowRoot = shadow;\n\n helpers.setShadowRoot(shadow);\n };\n\n const cardMappingOptions: CardMappingOptions = {\n isThemeDark,\n isTransparent,\n isOverlay,\n isAligned,\n imageConfig,\n ...(cardType && { cardType }),\n };\n\n const layoutElement = layoutStrategy.create({\n columns: numberOfColumnsToShow as 2 | 3 | 4,\n isThemeDark,\n });\n helpers.setStyles(layoutElement.styles);\n\n const baseProps = {\n token,\n categories,\n ids,\n entriesToRemove,\n numberOfColumnsToShow,\n numberOfRowsToStart,\n isLazyLoad,\n isMediaTrained,\n getOffset: helpers.getOffset,\n };\n\n // Create a mutable reference for lazy load callback\n // This allows us to set it after fetchHandlers are created\n const lazyLoadCallbackRef = {\n current: undefined as (() => Promise<void>) | undefined,\n };\n\n // Create display handlers with callback reference\n const displayHandlers = createDisplayHandlers({\n displayStrategy,\n layoutStrategy,\n helpers,\n cardMappingOptions,\n isLazyLoad,\n numberOfColumnsToShow,\n numberOfRowsToStart,\n noResultsConfig: {\n ...noResultsConfig,\n isThemeDark, // Ensure theme is passed to EmptyState\n },\n // Pass a function that calls the current callback\n lazyLoadCallback: isLazyLoad\n ? async () => {\n if (lazyLoadCallbackRef.current) {\n await lazyLoadCallbackRef.current();\n }\n }\n : undefined,\n });\n\n // Create fetch handlers\n const fetchHandlers = createFetchHandlers({\n fetchStrategy,\n helpers,\n baseProps,\n displayHandlers,\n layoutElement,\n isThemeDark,\n enableCategoryFallback,\n });\n\n // Set the lazy load callback reference now that fetch handlers exist\n lazyLoadCallbackRef.current = fetchHandlers.loadMore;\n\n // Append loading indicator to container\n container.appendChild(loading.element);\n\n // Start fetching data\n fetchHandlers.start();\n\n // Return feed with getter for styles to ensure dynamic access\n return {\n element: container,\n get styles() {\n return styles;\n },\n events: {\n callback: shadowRootCallback,\n },\n };\n}\n"],"names":[],"mappings":";;;;;;;;AAwDO,SAAS,eACd,QACmB;AACnB,QAAM;AAAA,IACJ;AAAA,IACA,cAAc;AAAA,IACd,gBAAgB;AAAA,IAChB,YAAY;AAAA,IACZ,YAAY;AAAA,IACZ,iBAAiB;AAAA,IACjB;AAAA,IACA,wBAAwB;AAAA,IACxB;AAAA,IACA,aAAa;AAAA,IACb,yBAAyB;AAAA,IACzB;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EAAA,IACE;AAEJ,QAAM,YAAY,SAAS,cAAc,KAAK;AAC9C,QAAM,UAAU,IAAI,aAAa,EAAE,aAAa;AAChD,MAAI,SAAS,QAAQ;AAGrB,QAAM,UAAU,kBAAkB;AAAA,IAChC;AAAA,IACA,eAAe;AAAA,EAAA,CAChB;AAGD,QAAM,oBAAoB,QAAQ;AAClC,UAAQ,YAAY,CAAC,qBAA6B;AAChD,cAAU;AACV,sBAAkB,gBAAgB;AAAA,EACpC;AAIA,QAAM,qBAAqB,CAAC,WAAuB;AAGjD,YAAQ,cAAc,MAAM;AAAA,EAC9B;AAEA,QAAM,qBAAyC;AAAA,IAC7C;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA,GAAI,YAAY,EAAE,SAAA;AAAA,EAAS;AAG7B,QAAM,gBAAgB,eAAe,OAAO;AAAA,IAC1C,SAAS;AAAA,IACT;AAAA,EAAA,CACD;AACD,UAAQ,UAAU,cAAc,MAAM;AAEtC,QAAM,YAAY;AAAA,IAChB;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA,WAAW,QAAQ;AAAA,EAAA;AAKrB,QAAM,sBAAsB;AAAA,IAC1B,SAAS;AAAA,EAAA;AAIX,QAAM,kBAAkB,sBAAsB;AAAA,IAC5C;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA,iBAAiB;AAAA,MACf,GAAG;AAAA,MACH;AAAA;AAAA,IAAA;AAAA;AAAA,IAGF,kBAAkB,aACd,YAAY;AACV,UAAI,oBAAoB,SAAS;AAC/B,cAAM,oBAAoB,QAAA;AAAA,MAC5B;AAAA,IACF,IACA;AAAA,EAAA,CACL;AAGD,QAAM,gBAAgB,oBAAoB;AAAA,IACxC;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EAAA,CACD;AAGD,sBAAoB,UAAU,cAAc;AAG5C,YAAU,YAAY,QAAQ,OAAO;AAGrC,gBAAc,MAAA;AAGd,SAAO;AAAA,IACL,SAAS;AAAA,IACT,IAAI,SAAS;AACX,aAAO;AAAA,IACT;AAAA,IACA,QAAQ;AAAA,MACN,UAAU;AAAA,IAAA;AAAA,EACZ;AAEJ;"}
@@ -66,6 +66,7 @@ export interface BaseFeedConfig<TData, TVariables = any> {
66
66
  enableCategoryFallback?: boolean;
67
67
  isMediaTrained?: boolean | null;
68
68
  categories?: string[];
69
+ ids?: string[];
69
70
  entriesToRemove?: Array<string | number>;
70
71
  fetchStrategy: FetchStrategy<TData, TVariables>;
71
72
  displayStrategy: DisplayStrategy<TData>;
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../source/factory/core/types.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../source/factory/core/types.ts"],"names":[],"mappings":"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"}
@@ -11,6 +11,7 @@ import "@universityofmaryland/web-utilities-library/network";
11
11
  import { eventsFetchStrategy } from "../../strategies/fetch/events.js";
12
12
  import "../../strategies/fetch/news.js";
13
13
  import "../../strategies/fetch/experts.js";
14
+ import "../../strategies/fetch/inTheNews.js";
14
15
  import { gridGapLayout } from "../../strategies/layout/grid.js";
15
16
  import "@universityofmaryland/web-elements-library/layout";
16
17
  const eventsGrid = (props) => createBaseFeed({
@@ -1 +1 @@
1
- {"version":3,"file":"grid.js","sources":["../../../source/feeds/events/grid.ts"],"sourcesContent":["/**\n * Events Grid Feed (Factory Pattern)\n *\n * Grid layout for event entries using the feed factory pattern.\n * This is the NEW implementation using factory + strategies.\n *\n * @module composite/events/grid-new\n */\n\nimport { createBaseFeed } from 'factory';\nimport {\n eventsFetchStrategy,\n eventsDisplayStrategy,\n gridGapLayout,\n} from 'strategies';\nimport { type BlockProps } from './_types';\nimport { type ElementModel } from '../../_types';\n\n/**\n * Create an events grid feed\n *\n * @param props - Feed configuration\n * @returns ElementModel with feed element and styles\n *\n * @example\n * ```typescript\n * const feed = eventsGrid({\n * token: 'my-token',\n * numberOfColumnsToShow: 3,\n * numberOfRowsToStart: 2,\n * isLazyLoad: true,\n * categories: ['sports', 'arts'],\n * });\n *\n * document.body.appendChild(feed.element);\n * ```\n */\nexport const eventsGrid = (props: BlockProps): ElementModel =>\n createBaseFeed({\n ...props,\n enableCategoryFallback: true,\n fetchStrategy: eventsFetchStrategy,\n displayStrategy: eventsDisplayStrategy,\n layoutStrategy: gridGapLayout,\n imageConfig: (entry) => ({\n imageUrl: entry.image[0].url,\n altText: entry.image[0].altText || 'Event Image',\n linkUrl: entry.url,\n linkLabel: 'University of Maryland Event',\n }),\n });\n"],"names":[],"mappings":";;;;;;;;;;;;;;;AAqCO,MAAM,aAAa,CAAC,UACzB,eAAe;AAAA,EACb,GAAG;AAAA,EACH,wBAAwB;AAAA,EACxB,eAAe;AAAA,EACf,iBAAiB;AAAA,EACjB,gBAAgB;AAAA,EAChB,aAAa,CAAC,WAAW;AAAA,IACvB,UAAU,MAAM,MAAM,CAAC,EAAE;AAAA,IACzB,SAAS,MAAM,MAAM,CAAC,EAAE,WAAW;AAAA,IACnC,SAAS,MAAM;AAAA,IACf,WAAW;AAAA,EAAA;AAEf,CAAC;"}
1
+ {"version":3,"file":"grid.js","sources":["../../../source/feeds/events/grid.ts"],"sourcesContent":["/**\n * Events Grid Feed (Factory Pattern)\n *\n * Grid layout for event entries using the feed factory pattern.\n * This is the NEW implementation using factory + strategies.\n *\n * @module composite/events/grid-new\n */\n\nimport { createBaseFeed } from 'factory';\nimport {\n eventsFetchStrategy,\n eventsDisplayStrategy,\n gridGapLayout,\n} from 'strategies';\nimport { type BlockProps } from './_types';\nimport { type ElementModel } from '../../_types';\n\n/**\n * Create an events grid feed\n *\n * @param props - Feed configuration\n * @returns ElementModel with feed element and styles\n *\n * @example\n * ```typescript\n * const feed = eventsGrid({\n * token: 'my-token',\n * numberOfColumnsToShow: 3,\n * numberOfRowsToStart: 2,\n * isLazyLoad: true,\n * categories: ['sports', 'arts'],\n * });\n *\n * document.body.appendChild(feed.element);\n * ```\n */\nexport const eventsGrid = (props: BlockProps): ElementModel =>\n createBaseFeed({\n ...props,\n enableCategoryFallback: true,\n fetchStrategy: eventsFetchStrategy,\n displayStrategy: eventsDisplayStrategy,\n layoutStrategy: gridGapLayout,\n imageConfig: (entry) => ({\n imageUrl: entry.image[0].url,\n altText: entry.image[0].altText || 'Event Image',\n linkUrl: entry.url,\n linkLabel: 'University of Maryland Event',\n }),\n });\n"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAqCO,MAAM,aAAa,CAAC,UACzB,eAAe;AAAA,EACb,GAAG;AAAA,EACH,wBAAwB;AAAA,EACxB,eAAe;AAAA,EACf,iBAAiB;AAAA,EACjB,gBAAgB;AAAA,EAChB,aAAa,CAAC,WAAW;AAAA,IACvB,UAAU,MAAM,MAAM,CAAC,EAAE;AAAA,IACzB,SAAS,MAAM,MAAM,CAAC,EAAE,WAAW;AAAA,IACnC,SAAS,MAAM;AAAA,IACf,WAAW;AAAA,EAAA;AAEf,CAAC;"}
@@ -11,6 +11,7 @@ import "@universityofmaryland/web-utilities-library/network";
11
11
  import { eventsFetchStrategyRange } from "../../strategies/fetch/events.js";
12
12
  import "../../strategies/fetch/news.js";
13
13
  import "../../strategies/fetch/experts.js";
14
+ import "../../strategies/fetch/inTheNews.js";
14
15
  import "@universityofmaryland/web-elements-library/layout";
15
16
  import { dispatch, eventNames } from "../../helpers/events/index.js";
16
17
  import { groupEventsByDate } from "../../helpers/grouping/events.js";
@@ -1 +1 @@
1
- {"version":3,"file":"grouped.js","sources":["../../../source/feeds/events/grouped.ts"],"sourcesContent":["/**\n * Events Grouped Feed (Refactored with Element Builder)\n *\n * Grouped layout for event entries organized by date with dynamic headers.\n * Uses Element Builder pattern with custom grouping logic for date-based organization.\n *\n * @module feeds/events/grouped\n */\n\nimport * as Styles from '@universityofmaryland/web-styles-library';\nimport { ElementBuilder } from '@universityofmaryland/web-builder-library';\nimport { card } from '@universityofmaryland/web-elements-library/composite';\nimport { events as eventElements } from '@universityofmaryland/web-elements-library/atomic';\nimport {\n createTextWithLink,\n createTextContainer,\n createImageOrLinkedImage,\n} from '@universityofmaryland/web-utilities-library/elements';\nimport { LoadingState, PaginationState, EmptyState, Announcer } from 'states';\nimport { eventsFetchStrategyRange } from 'strategies';\nimport { type EventEntry } from 'types/data';\nimport {\n grouping,\n events as eventUtilities,\n styles as styleUtilities,\n} from '../../helpers';\nimport { type ListProps } from './_types';\nimport { type ElementModel } from '../../_types';\n\n// ============================================================================\n// PURE HELPER FUNCTIONS\n// ============================================================================\n\n/**\n * Create base props for fetch strategy\n *\n * @param props - Feed props\n * @param offset - Current offset\n * @returns Base props object for strategy's composeApiVariables\n */\nconst createFetchProps = (\n props: Pick<ListProps, 'token' | 'categories' | 'numberOfRowsToStart'>,\n offset: number,\n) => ({\n token: props.token,\n categories: props.categories,\n numberOfColumnsToShow: 1,\n numberOfRowsToStart: props.numberOfRowsToStart,\n getOffset: () => offset,\n});\n\n/**\n * Create image configuration for event entry\n *\n * @param entry - Event entry\n * @returns Image config object\n */\nconst createImageConfig = (entry: EventEntry) => ({\n imageUrl: entry.image[0].url,\n altText: entry.image[0].altText || 'Event Image',\n linkUrl: entry.url,\n linkLabel: 'University of Maryland Event',\n});\n\n/**\n * Create announcer message\n *\n * @param count - Number of events shown\n * @param total - Total events\n * @param isLazyLoad - Lazy load enabled\n * @returns Announcer message\n */\nconst createAnnouncerMessage = (\n count: number,\n total: number,\n isLazyLoad: boolean,\n): string => {\n return isLazyLoad\n ? `Showing ${count} of ${total} events`\n : `Showing ${count} events`;\n};\n\n// ============================================================================\n// STATE MANAGER CLASS\n// ============================================================================\n\n/**\n * Manages grouped feed state and shadow DOM synchronization\n *\n * Encapsulates all mutable state including offset, total,\n * last date headline tracking, and shadow DOM management.\n */\nclass GroupedFeedState {\n private stylesArray: string[] = [];\n private shadowRoot: ShadowRoot | null = null;\n private totalEntries: number = 0;\n private offset: number = 0;\n private lastDateHeadline: string | null = null;\n\n /**\n * Initialize state with initial styles\n *\n * @param initialStyles - Initial CSS styles\n */\n constructor(initialStyles: string) {\n this.stylesArray.push(initialStyles);\n }\n\n /**\n * Add styles to the accumulated styles\n *\n * @param styles - CSS styles to add\n */\n addStyles(styles: string): void {\n this.stylesArray.push(styles);\n }\n\n /**\n * Set shadow root reference for style updates\n *\n * @param shadow - Shadow root element\n */\n setShadowRoot(shadow: ShadowRoot): void {\n this.shadowRoot = shadow;\n }\n\n /**\n * Update shadow DOM styles\n *\n * @returns Promise that resolves when styles are updated\n */\n async updateShadowStyles(): Promise<void> {\n if (!this.shadowRoot) return;\n await styleUtilities.setShadowStyles({\n shadowRoot: this.shadowRoot,\n styles: this.getStyles(),\n });\n }\n\n /**\n * Get accumulated styles as single string\n *\n * @returns Combined CSS styles\n */\n getStyles(): string {\n return this.stylesArray.join('\\n');\n }\n\n /**\n * Get shadow root callback for events\n *\n * @returns Callback function for shadow root\n */\n getShadowCallback(): (shadow: ShadowRoot) => void {\n return (shadow) => this.setShadowRoot(shadow);\n }\n\n /**\n * Get current offset\n *\n * @returns Current offset\n */\n getOffset(): number {\n return this.offset;\n }\n\n /**\n * Increment offset by count\n *\n * @param count - Number to increment by\n */\n incrementOffset(count: number): void {\n this.offset += count;\n }\n\n /**\n * Get total entries\n *\n * @returns Total entries\n */\n getTotalEntries(): number {\n return this.totalEntries;\n }\n\n /**\n * Set total entries\n *\n * @param total - Total entries\n */\n setTotalEntries(total: number): void {\n this.totalEntries = total;\n }\n\n /**\n * Get last date headline\n *\n * @returns Last date headline or null\n */\n getLastDateHeadline(): string | null {\n return this.lastDateHeadline;\n }\n\n /**\n * Set last date headline\n *\n * @param headline - Date headline\n */\n setLastDateHeadline(headline: string): void {\n this.lastDateHeadline = headline;\n }\n}\n\n// ============================================================================\n// RENDERING FUNCTIONS\n// ============================================================================\n\n/**\n * Create date header element\n *\n * @param date - Date string\n * @param state - State manager\n * @returns Date header element model\n */\nconst createDateHeader = (\n date: string,\n state: GroupedFeedState,\n): ElementModel => {\n const dateHeadline = document.createElement('p');\n dateHeadline.textContent = date;\n\n const headerElement = new ElementBuilder(dateHeadline)\n .styled(Styles.element.text.decoration.ribbon)\n .withStyles({\n element: {\n margin: `${Styles.token.spacing.lg} 0`,\n },\n })\n .build();\n\n state.addStyles(headerElement.styles);\n return headerElement;\n};\n\n/**\n * Create event card for grouped display\n *\n * @param entry - Event entry\n * @param isThemeDark - Dark theme flag\n * @returns Event card element model\n */\nconst createEventCard = (\n entry: EventEntry,\n isThemeDark: boolean,\n): ElementModel => {\n return card.list({\n headline: createTextWithLink({ text: entry.title, url: entry.url }),\n text: createTextContainer({ text: entry.summary, allowHTML: true }),\n dateSign: eventElements.sign({\n startMonth: entry.startMonth,\n startDay: entry.startDay,\n endMonth: entry.endMonth,\n endDay: entry.endDay,\n isThemeDark,\n isLargeSize: true,\n }),\n eventMeta: eventElements.meta({\n ...entry,\n isThemeDark,\n } as any),\n image: createImageOrLinkedImage(createImageConfig(entry)),\n isAligned: false,\n isThemeDark,\n });\n};\n\n/**\n * Create group container with entries\n *\n * @param events - Event entries for this group\n * @param state - State manager\n * @param isThemeDark - Dark theme flag\n * @returns Group container element model\n */\nconst createGroupContainer = (\n events: EventEntry[],\n state: GroupedFeedState,\n isThemeDark: boolean,\n): ElementModel => {\n const entriesBuilder = new ElementBuilder('div')\n .withClassName('umd-feed-events-grouped-entries')\n .withStyles({\n element: {\n [` > *:not(:last-child)`]: {\n paddingBottom: Styles.token.spacing.md,\n marginBottom: Styles.token.spacing.md,\n borderBottom: `1px solid ${\n isThemeDark\n ? Styles.token.color.gray.dark\n : Styles.token.color.gray.light\n }`,\n },\n [`+ .umd-feed-events-grouped-entries`]: {\n paddingTop: Styles.token.spacing.md,\n marginTop: Styles.token.spacing.md,\n borderTop: `1px solid ${\n isThemeDark\n ? Styles.token.color.gray.dark\n : Styles.token.color.gray.light\n }`,\n },\n },\n });\n\n // Create cards for each event\n events.forEach((entry) => {\n const eventCard = createEventCard(entry, isThemeDark);\n entriesBuilder.withChild(eventCard);\n state.addStyles(eventCard.styles);\n });\n\n const groupElement = entriesBuilder.build();\n state.addStyles(groupElement.styles);\n\n return groupElement;\n};\n\n/**\n * Render grouped events\n *\n * @param container - Container element\n * @param events - Event entries\n * @param state - State manager\n * @param isThemeDark - Dark theme flag\n * @param isLazyLoad - Lazy load enabled\n * @param loadMore - Load more callback\n * @returns Promise that resolves when rendering is complete\n */\nconst renderGroupedEvents = async (\n container: HTMLElement,\n events: EventEntry[],\n state: GroupedFeedState,\n isThemeDark: boolean,\n isLazyLoad: boolean,\n loadMore: () => Promise<void>,\n): Promise<void> => {\n const grid = container.querySelector(\n '#umd-feed-events-grouped-container',\n ) as HTMLElement;\n if (!grid) return;\n\n // Remove existing states\n container.querySelector('.umd-loader-container')?.remove();\n container\n .querySelector(`.${Styles.layout.alignment.block.center.className}`)\n ?.remove();\n\n // Group events by date\n const groupedEvents = grouping.groupEventsByDate(events);\n let actualEventCount = 0;\n\n groupedEvents.forEach((group) => {\n // Add date header if it's a new date\n if (group.date !== state.getLastDateHeadline()) {\n const headerElement = createDateHeader(group.date, state);\n grid.appendChild(headerElement.element);\n state.setLastDateHeadline(group.date);\n }\n\n // Create group container with entries\n const groupElement = createGroupContainer(group.events, state, isThemeDark);\n grid.appendChild(groupElement.element);\n\n actualEventCount += group.events.length;\n });\n\n // Update offset with actual event count\n state.incrementOffset(actualEventCount);\n\n // Add pagination if lazy load enabled\n if (isLazyLoad && state.getTotalEntries() > state.getOffset()) {\n const pagination = new PaginationState({\n totalEntries: state.getTotalEntries(),\n offset: state.getOffset(),\n isLazyLoad: true,\n callback: loadMore,\n });\n\n const paginationElement = pagination.render(container);\n if (paginationElement) {\n state.addStyles(paginationElement.styles);\n }\n }\n\n // Update shadow root styles\n await state.updateShadowStyles();\n};\n\n/**\n * Render error state\n *\n * @param container - Container element\n * @param state - State manager\n * @param isThemeDark - Dark theme flag\n * @returns Promise that resolves when rendering is complete\n */\nconst renderError = async (\n container: HTMLElement,\n state: GroupedFeedState,\n isThemeDark: boolean,\n): Promise<void> => {\n const emptyState = new EmptyState({\n message: 'No events found',\n isThemeDark,\n });\n emptyState.render(container);\n state.addStyles(emptyState.styles);\n\n const announcer = new Announcer({ message: 'No events found' });\n container.appendChild(announcer.getElement());\n\n eventUtilities.dispatch(container, eventUtilities.eventNames.FEED_ERROR, {\n error: 'No results found',\n });\n\n await state.updateShadowStyles();\n};\n\n// ============================================================================\n// MAIN EXPORT\n// ============================================================================\n\n/**\n * Create a grouped events feed\n *\n * Groups events by date with dynamic date headers (Today, day names, formatted dates).\n * Events are sorted by priority within each group (multi-day events starting today first).\n * Uses Element Builder pattern for clean construction.\n *\n * @param props - Feed configuration\n * @returns ElementModel with feed element and styles\n *\n * @example\n * ```typescript\n * const feed = eventsGrouped({\n * token: 'my-token',\n * numberOfRowsToStart: 10,\n * isLazyLoad: true,\n * });\n * ```\n *\n * @example\n * ```typescript\n * // With dark theme\n * const feed = eventsGrouped({\n * token: 'my-token',\n * numberOfRowsToStart: 20,\n * isThemeDark: true,\n * });\n * ```\n */\nexport const eventsGrouped = (props: ListProps): ElementModel => {\n const {\n token,\n isThemeDark = false,\n isLazyLoad = false,\n numberOfRowsToStart,\n categories,\n } = props;\n\n // Create container using ElementBuilder\n const containerBuilder = new ElementBuilder('div').withClassName(\n 'events-grouped-feed',\n );\n\n // Get element for manipulation (non-destructive)\n const container = containerBuilder.getElement();\n\n // Initialize state management\n const loading = new LoadingState({ isThemeDark });\n const state = new GroupedFeedState(loading.styles);\n\n // Create layout\n const layoutElement = new ElementBuilder('div')\n .withClassName('umd-feed-events-grouped')\n .build();\n state.addStyles(layoutElement.styles);\n\n /**\n * Load more events (for lazy loading)\n */\n const loadMore = async (): Promise<void> => {\n const fetchProps = createFetchProps(\n { token, categories, numberOfRowsToStart },\n state.getOffset(),\n );\n const variables = eventsFetchStrategyRange.composeApiVariables(fetchProps);\n\n const entries = await eventsFetchStrategyRange.fetchEntries(variables);\n if (entries && entries.length > 0) {\n await renderGroupedEvents(\n container,\n entries,\n state,\n isThemeDark,\n isLazyLoad,\n loadMore,\n );\n }\n };\n\n /**\n * Initialize feed\n */\n const initialize = async (): Promise<void> => {\n loading.show(container);\n\n const fetchProps = createFetchProps(\n { token, categories, numberOfRowsToStart },\n 0,\n );\n const variables = eventsFetchStrategyRange.composeApiVariables(fetchProps);\n\n // Fetch count and entries\n const [count, entries] = await Promise.all([\n eventsFetchStrategyRange.fetchCount(variables),\n eventsFetchStrategyRange.fetchEntries(variables),\n ]);\n\n // Remove loading\n loading.hide();\n\n // Handle no results\n if (!entries || entries.length === 0) {\n await renderError(container, state, isThemeDark);\n return;\n }\n\n // Set total and append layout\n state.setTotalEntries(count || entries.length);\n layoutElement.element.setAttribute(\n 'id',\n 'umd-feed-events-grouped-container',\n );\n container.appendChild(layoutElement.element);\n\n // Dispatch loaded event\n eventUtilities.dispatch(container, eventUtilities.eventNames.FEED_LOADED, {\n items: entries,\n count: entries.length,\n total: state.getTotalEntries(),\n });\n\n // Render grouped events\n await renderGroupedEvents(\n container,\n entries,\n state,\n isThemeDark,\n isLazyLoad,\n loadMore,\n );\n\n // Add announcer\n const message = createAnnouncerMessage(\n entries.length,\n state.getTotalEntries(),\n isLazyLoad,\n );\n const announcer = new Announcer({ message });\n container.appendChild(announcer.getElement());\n };\n\n // Start initialization\n initialize();\n\n // Build and return element model\n const model = containerBuilder.build();\n\n return {\n element: model.element,\n get styles() {\n return state.getStyles();\n },\n events: {\n callback: state.getShadowCallback(),\n },\n };\n};\n"],"names":["styleUtilities.setShadowStyles","eventElements","events","grouping.groupEventsByDate","eventUtilities.dispatch","eventUtilities.eventNames"],"mappings":"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"}
1
+ {"version":3,"file":"grouped.js","sources":["../../../source/feeds/events/grouped.ts"],"sourcesContent":["/**\n * Events Grouped Feed (Refactored with Element Builder)\n *\n * Grouped layout for event entries organized by date with dynamic headers.\n * Uses Element Builder pattern with custom grouping logic for date-based organization.\n *\n * @module feeds/events/grouped\n */\n\nimport * as Styles from '@universityofmaryland/web-styles-library';\nimport { ElementBuilder } from '@universityofmaryland/web-builder-library';\nimport { card } from '@universityofmaryland/web-elements-library/composite';\nimport { events as eventElements } from '@universityofmaryland/web-elements-library/atomic';\nimport {\n createTextWithLink,\n createTextContainer,\n createImageOrLinkedImage,\n} from '@universityofmaryland/web-utilities-library/elements';\nimport { LoadingState, PaginationState, EmptyState, Announcer } from 'states';\nimport { eventsFetchStrategyRange } from 'strategies';\nimport { type EventEntry } from 'types/data';\nimport {\n grouping,\n events as eventUtilities,\n styles as styleUtilities,\n} from '../../helpers';\nimport { type ListProps } from './_types';\nimport { type ElementModel } from '../../_types';\n\n// ============================================================================\n// PURE HELPER FUNCTIONS\n// ============================================================================\n\n/**\n * Create base props for fetch strategy\n *\n * @param props - Feed props\n * @param offset - Current offset\n * @returns Base props object for strategy's composeApiVariables\n */\nconst createFetchProps = (\n props: Pick<ListProps, 'token' | 'categories' | 'numberOfRowsToStart'>,\n offset: number,\n) => ({\n token: props.token,\n categories: props.categories,\n numberOfColumnsToShow: 1,\n numberOfRowsToStart: props.numberOfRowsToStart,\n getOffset: () => offset,\n});\n\n/**\n * Create image configuration for event entry\n *\n * @param entry - Event entry\n * @returns Image config object\n */\nconst createImageConfig = (entry: EventEntry) => ({\n imageUrl: entry.image[0].url,\n altText: entry.image[0].altText || 'Event Image',\n linkUrl: entry.url,\n linkLabel: 'University of Maryland Event',\n});\n\n/**\n * Create announcer message\n *\n * @param count - Number of events shown\n * @param total - Total events\n * @param isLazyLoad - Lazy load enabled\n * @returns Announcer message\n */\nconst createAnnouncerMessage = (\n count: number,\n total: number,\n isLazyLoad: boolean,\n): string => {\n return isLazyLoad\n ? `Showing ${count} of ${total} events`\n : `Showing ${count} events`;\n};\n\n// ============================================================================\n// STATE MANAGER CLASS\n// ============================================================================\n\n/**\n * Manages grouped feed state and shadow DOM synchronization\n *\n * Encapsulates all mutable state including offset, total,\n * last date headline tracking, and shadow DOM management.\n */\nclass GroupedFeedState {\n private stylesArray: string[] = [];\n private shadowRoot: ShadowRoot | null = null;\n private totalEntries: number = 0;\n private offset: number = 0;\n private lastDateHeadline: string | null = null;\n\n /**\n * Initialize state with initial styles\n *\n * @param initialStyles - Initial CSS styles\n */\n constructor(initialStyles: string) {\n this.stylesArray.push(initialStyles);\n }\n\n /**\n * Add styles to the accumulated styles\n *\n * @param styles - CSS styles to add\n */\n addStyles(styles: string): void {\n this.stylesArray.push(styles);\n }\n\n /**\n * Set shadow root reference for style updates\n *\n * @param shadow - Shadow root element\n */\n setShadowRoot(shadow: ShadowRoot): void {\n this.shadowRoot = shadow;\n }\n\n /**\n * Update shadow DOM styles\n *\n * @returns Promise that resolves when styles are updated\n */\n async updateShadowStyles(): Promise<void> {\n if (!this.shadowRoot) return;\n await styleUtilities.setShadowStyles({\n shadowRoot: this.shadowRoot,\n styles: this.getStyles(),\n });\n }\n\n /**\n * Get accumulated styles as single string\n *\n * @returns Combined CSS styles\n */\n getStyles(): string {\n return this.stylesArray.join('\\n');\n }\n\n /**\n * Get shadow root callback for events\n *\n * @returns Callback function for shadow root\n */\n getShadowCallback(): (shadow: ShadowRoot) => void {\n return (shadow) => this.setShadowRoot(shadow);\n }\n\n /**\n * Get current offset\n *\n * @returns Current offset\n */\n getOffset(): number {\n return this.offset;\n }\n\n /**\n * Increment offset by count\n *\n * @param count - Number to increment by\n */\n incrementOffset(count: number): void {\n this.offset += count;\n }\n\n /**\n * Get total entries\n *\n * @returns Total entries\n */\n getTotalEntries(): number {\n return this.totalEntries;\n }\n\n /**\n * Set total entries\n *\n * @param total - Total entries\n */\n setTotalEntries(total: number): void {\n this.totalEntries = total;\n }\n\n /**\n * Get last date headline\n *\n * @returns Last date headline or null\n */\n getLastDateHeadline(): string | null {\n return this.lastDateHeadline;\n }\n\n /**\n * Set last date headline\n *\n * @param headline - Date headline\n */\n setLastDateHeadline(headline: string): void {\n this.lastDateHeadline = headline;\n }\n}\n\n// ============================================================================\n// RENDERING FUNCTIONS\n// ============================================================================\n\n/**\n * Create date header element\n *\n * @param date - Date string\n * @param state - State manager\n * @returns Date header element model\n */\nconst createDateHeader = (\n date: string,\n state: GroupedFeedState,\n): ElementModel => {\n const dateHeadline = document.createElement('p');\n dateHeadline.textContent = date;\n\n const headerElement = new ElementBuilder(dateHeadline)\n .styled(Styles.element.text.decoration.ribbon)\n .withStyles({\n element: {\n margin: `${Styles.token.spacing.lg} 0`,\n },\n })\n .build();\n\n state.addStyles(headerElement.styles);\n return headerElement;\n};\n\n/**\n * Create event card for grouped display\n *\n * @param entry - Event entry\n * @param isThemeDark - Dark theme flag\n * @returns Event card element model\n */\nconst createEventCard = (\n entry: EventEntry,\n isThemeDark: boolean,\n): ElementModel => {\n return card.list({\n headline: createTextWithLink({ text: entry.title, url: entry.url }),\n text: createTextContainer({ text: entry.summary, allowHTML: true }),\n dateSign: eventElements.sign({\n startMonth: entry.startMonth,\n startDay: entry.startDay,\n endMonth: entry.endMonth,\n endDay: entry.endDay,\n isThemeDark,\n isLargeSize: true,\n }),\n eventMeta: eventElements.meta({\n ...entry,\n isThemeDark,\n } as any),\n image: createImageOrLinkedImage(createImageConfig(entry)),\n isAligned: false,\n isThemeDark,\n });\n};\n\n/**\n * Create group container with entries\n *\n * @param events - Event entries for this group\n * @param state - State manager\n * @param isThemeDark - Dark theme flag\n * @returns Group container element model\n */\nconst createGroupContainer = (\n events: EventEntry[],\n state: GroupedFeedState,\n isThemeDark: boolean,\n): ElementModel => {\n const entriesBuilder = new ElementBuilder('div')\n .withClassName('umd-feed-events-grouped-entries')\n .withStyles({\n element: {\n [` > *:not(:last-child)`]: {\n paddingBottom: Styles.token.spacing.md,\n marginBottom: Styles.token.spacing.md,\n borderBottom: `1px solid ${\n isThemeDark\n ? Styles.token.color.gray.dark\n : Styles.token.color.gray.light\n }`,\n },\n [`+ .umd-feed-events-grouped-entries`]: {\n paddingTop: Styles.token.spacing.md,\n marginTop: Styles.token.spacing.md,\n borderTop: `1px solid ${\n isThemeDark\n ? Styles.token.color.gray.dark\n : Styles.token.color.gray.light\n }`,\n },\n },\n });\n\n // Create cards for each event\n events.forEach((entry) => {\n const eventCard = createEventCard(entry, isThemeDark);\n entriesBuilder.withChild(eventCard);\n state.addStyles(eventCard.styles);\n });\n\n const groupElement = entriesBuilder.build();\n state.addStyles(groupElement.styles);\n\n return groupElement;\n};\n\n/**\n * Render grouped events\n *\n * @param container - Container element\n * @param events - Event entries\n * @param state - State manager\n * @param isThemeDark - Dark theme flag\n * @param isLazyLoad - Lazy load enabled\n * @param loadMore - Load more callback\n * @returns Promise that resolves when rendering is complete\n */\nconst renderGroupedEvents = async (\n container: HTMLElement,\n events: EventEntry[],\n state: GroupedFeedState,\n isThemeDark: boolean,\n isLazyLoad: boolean,\n loadMore: () => Promise<void>,\n): Promise<void> => {\n const grid = container.querySelector(\n '#umd-feed-events-grouped-container',\n ) as HTMLElement;\n if (!grid) return;\n\n // Remove existing states\n container.querySelector('.umd-loader-container')?.remove();\n container\n .querySelector(`.${Styles.layout.alignment.block.center.className}`)\n ?.remove();\n\n // Group events by date\n const groupedEvents = grouping.groupEventsByDate(events);\n let actualEventCount = 0;\n\n groupedEvents.forEach((group) => {\n // Add date header if it's a new date\n if (group.date !== state.getLastDateHeadline()) {\n const headerElement = createDateHeader(group.date, state);\n grid.appendChild(headerElement.element);\n state.setLastDateHeadline(group.date);\n }\n\n // Create group container with entries\n const groupElement = createGroupContainer(group.events, state, isThemeDark);\n grid.appendChild(groupElement.element);\n\n actualEventCount += group.events.length;\n });\n\n // Update offset with actual event count\n state.incrementOffset(actualEventCount);\n\n // Add pagination if lazy load enabled\n if (isLazyLoad && state.getTotalEntries() > state.getOffset()) {\n const pagination = new PaginationState({\n totalEntries: state.getTotalEntries(),\n offset: state.getOffset(),\n isLazyLoad: true,\n callback: loadMore,\n });\n\n const paginationElement = pagination.render(container);\n if (paginationElement) {\n state.addStyles(paginationElement.styles);\n }\n }\n\n // Update shadow root styles\n await state.updateShadowStyles();\n};\n\n/**\n * Render error state\n *\n * @param container - Container element\n * @param state - State manager\n * @param isThemeDark - Dark theme flag\n * @returns Promise that resolves when rendering is complete\n */\nconst renderError = async (\n container: HTMLElement,\n state: GroupedFeedState,\n isThemeDark: boolean,\n): Promise<void> => {\n const emptyState = new EmptyState({\n message: 'No events found',\n isThemeDark,\n });\n emptyState.render(container);\n state.addStyles(emptyState.styles);\n\n const announcer = new Announcer({ message: 'No events found' });\n container.appendChild(announcer.getElement());\n\n eventUtilities.dispatch(container, eventUtilities.eventNames.FEED_ERROR, {\n error: 'No results found',\n });\n\n await state.updateShadowStyles();\n};\n\n// ============================================================================\n// MAIN EXPORT\n// ============================================================================\n\n/**\n * Create a grouped events feed\n *\n * Groups events by date with dynamic date headers (Today, day names, formatted dates).\n * Events are sorted by priority within each group (multi-day events starting today first).\n * Uses Element Builder pattern for clean construction.\n *\n * @param props - Feed configuration\n * @returns ElementModel with feed element and styles\n *\n * @example\n * ```typescript\n * const feed = eventsGrouped({\n * token: 'my-token',\n * numberOfRowsToStart: 10,\n * isLazyLoad: true,\n * });\n * ```\n *\n * @example\n * ```typescript\n * // With dark theme\n * const feed = eventsGrouped({\n * token: 'my-token',\n * numberOfRowsToStart: 20,\n * isThemeDark: true,\n * });\n * ```\n */\nexport const eventsGrouped = (props: ListProps): ElementModel => {\n const {\n token,\n isThemeDark = false,\n isLazyLoad = false,\n numberOfRowsToStart,\n categories,\n } = props;\n\n // Create container using ElementBuilder\n const containerBuilder = new ElementBuilder('div').withClassName(\n 'events-grouped-feed',\n );\n\n // Get element for manipulation (non-destructive)\n const container = containerBuilder.getElement();\n\n // Initialize state management\n const loading = new LoadingState({ isThemeDark });\n const state = new GroupedFeedState(loading.styles);\n\n // Create layout\n const layoutElement = new ElementBuilder('div')\n .withClassName('umd-feed-events-grouped')\n .build();\n state.addStyles(layoutElement.styles);\n\n /**\n * Load more events (for lazy loading)\n */\n const loadMore = async (): Promise<void> => {\n const fetchProps = createFetchProps(\n { token, categories, numberOfRowsToStart },\n state.getOffset(),\n );\n const variables = eventsFetchStrategyRange.composeApiVariables(fetchProps);\n\n const entries = await eventsFetchStrategyRange.fetchEntries(variables);\n if (entries && entries.length > 0) {\n await renderGroupedEvents(\n container,\n entries,\n state,\n isThemeDark,\n isLazyLoad,\n loadMore,\n );\n }\n };\n\n /**\n * Initialize feed\n */\n const initialize = async (): Promise<void> => {\n loading.show(container);\n\n const fetchProps = createFetchProps(\n { token, categories, numberOfRowsToStart },\n 0,\n );\n const variables = eventsFetchStrategyRange.composeApiVariables(fetchProps);\n\n // Fetch count and entries\n const [count, entries] = await Promise.all([\n eventsFetchStrategyRange.fetchCount(variables),\n eventsFetchStrategyRange.fetchEntries(variables),\n ]);\n\n // Remove loading\n loading.hide();\n\n // Handle no results\n if (!entries || entries.length === 0) {\n await renderError(container, state, isThemeDark);\n return;\n }\n\n // Set total and append layout\n state.setTotalEntries(count || entries.length);\n layoutElement.element.setAttribute(\n 'id',\n 'umd-feed-events-grouped-container',\n );\n container.appendChild(layoutElement.element);\n\n // Dispatch loaded event\n eventUtilities.dispatch(container, eventUtilities.eventNames.FEED_LOADED, {\n items: entries,\n count: entries.length,\n total: state.getTotalEntries(),\n });\n\n // Render grouped events\n await renderGroupedEvents(\n container,\n entries,\n state,\n isThemeDark,\n isLazyLoad,\n loadMore,\n );\n\n // Add announcer\n const message = createAnnouncerMessage(\n entries.length,\n state.getTotalEntries(),\n isLazyLoad,\n );\n const announcer = new Announcer({ message });\n container.appendChild(announcer.getElement());\n };\n\n // Start initialization\n initialize();\n\n // Build and return element model\n const model = containerBuilder.build();\n\n return {\n element: model.element,\n get styles() {\n return state.getStyles();\n },\n events: {\n callback: state.getShadowCallback(),\n },\n };\n};\n"],"names":["styleUtilities.setShadowStyles","eventElements","events","grouping.groupEventsByDate","eventUtilities.dispatch","eventUtilities.eventNames"],"mappings":"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"}
@@ -11,6 +11,7 @@ import "@universityofmaryland/web-utilities-library/network";
11
11
  import { eventsFetchStrategy } from "../../strategies/fetch/events.js";
12
12
  import "../../strategies/fetch/news.js";
13
13
  import "../../strategies/fetch/experts.js";
14
+ import "../../strategies/fetch/inTheNews.js";
14
15
  import { stackedLayout } from "../../strategies/layout/grid.js";
15
16
  import "@universityofmaryland/web-elements-library/layout";
16
17
  const eventsList = (props) => createBaseFeed({
@@ -1 +1 @@
1
- {"version":3,"file":"list.js","sources":["../../../source/feeds/events/list.ts"],"sourcesContent":["/**\n * Events List Feed (Factory Pattern)\n *\n * List layout for event entries using the feed factory pattern.\n * This is the NEW implementation using factory + strategies.\n *\n * @module composite/events/list-new\n */\n\nimport { createBaseFeed } from 'factory';\nimport {\n eventsFetchStrategy,\n eventsDisplayStrategy,\n stackedLayout,\n} from 'strategies';\nimport { type ListProps } from './_types';\nimport { type ElementModel } from '../../_types';\n\n/**\n * Create an events list feed\n *\n * @param props - Feed configuration\n * @returns ElementModel with feed element and styles\n *\n * @example\n * ```typescript\n * const feed = eventsList({\n * token: 'my-token',\n * numberOfRowsToStart: 5,\n * isLazyLoad: true,\n * categories: ['sports', 'arts'],\n * });\n *\n * document.body.appendChild(feed.element);\n * ```\n */\nexport const eventsList = (props: ListProps): ElementModel =>\n createBaseFeed({\n ...props,\n enableCategoryFallback: true,\n cardType: 'list',\n fetchStrategy: eventsFetchStrategy,\n displayStrategy: eventsDisplayStrategy,\n layoutStrategy: stackedLayout,\n imageConfig: (entry) => ({\n imageUrl: entry.image[0].url,\n altText: entry.image[0].altText || 'Event Image',\n linkUrl: entry.url,\n linkLabel: 'University of Maryland Event',\n }),\n });\n"],"names":[],"mappings":";;;;;;;;;;;;;;;AAoCO,MAAM,aAAa,CAAC,UACzB,eAAe;AAAA,EACb,GAAG;AAAA,EACH,wBAAwB;AAAA,EACxB,UAAU;AAAA,EACV,eAAe;AAAA,EACf,iBAAiB;AAAA,EACjB,gBAAgB;AAAA,EAChB,aAAa,CAAC,WAAW;AAAA,IACvB,UAAU,MAAM,MAAM,CAAC,EAAE;AAAA,IACzB,SAAS,MAAM,MAAM,CAAC,EAAE,WAAW;AAAA,IACnC,SAAS,MAAM;AAAA,IACf,WAAW;AAAA,EAAA;AAEf,CAAC;"}
1
+ {"version":3,"file":"list.js","sources":["../../../source/feeds/events/list.ts"],"sourcesContent":["/**\n * Events List Feed (Factory Pattern)\n *\n * List layout for event entries using the feed factory pattern.\n * This is the NEW implementation using factory + strategies.\n *\n * @module composite/events/list-new\n */\n\nimport { createBaseFeed } from 'factory';\nimport {\n eventsFetchStrategy,\n eventsDisplayStrategy,\n stackedLayout,\n} from 'strategies';\nimport { type ListProps } from './_types';\nimport { type ElementModel } from '../../_types';\n\n/**\n * Create an events list feed\n *\n * @param props - Feed configuration\n * @returns ElementModel with feed element and styles\n *\n * @example\n * ```typescript\n * const feed = eventsList({\n * token: 'my-token',\n * numberOfRowsToStart: 5,\n * isLazyLoad: true,\n * categories: ['sports', 'arts'],\n * });\n *\n * document.body.appendChild(feed.element);\n * ```\n */\nexport const eventsList = (props: ListProps): ElementModel =>\n createBaseFeed({\n ...props,\n enableCategoryFallback: true,\n cardType: 'list',\n fetchStrategy: eventsFetchStrategy,\n displayStrategy: eventsDisplayStrategy,\n layoutStrategy: stackedLayout,\n imageConfig: (entry) => ({\n imageUrl: entry.image[0].url,\n altText: entry.image[0].altText || 'Event Image',\n linkUrl: entry.url,\n linkLabel: 'University of Maryland Event',\n }),\n });\n"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAoCO,MAAM,aAAa,CAAC,UACzB,eAAe;AAAA,EACb,GAAG;AAAA,EACH,wBAAwB;AAAA,EACxB,UAAU;AAAA,EACV,eAAe;AAAA,EACf,iBAAiB;AAAA,EACjB,gBAAgB;AAAA,EAChB,aAAa,CAAC,WAAW;AAAA,IACvB,UAAU,MAAM,MAAM,CAAC,EAAE;AAAA,IACzB,SAAS,MAAM,MAAM,CAAC,EAAE,WAAW;AAAA,IACnC,SAAS,MAAM;AAAA,IACf,WAAW;AAAA,EAAA;AAEf,CAAC;"}
@@ -3,9 +3,10 @@ export interface BaseProps {
3
3
  numberOfRowsToStart: number;
4
4
  categories?: string[];
5
5
  isThemeDark?: boolean;
6
- isMediaTrained?: boolean;
7
6
  isLazyLoad: boolean;
8
7
  entriesToRemove?: string[];
8
+ ids?: string[];
9
+ isMediaTrained?: boolean;
9
10
  styleCallback?: (cssString: string) => void;
10
11
  }
11
12
  export interface GridProps extends BaseProps {
@@ -17,7 +18,12 @@ export interface GridProps extends BaseProps {
17
18
  export interface ListProps extends BaseProps {
18
19
  cardType?: 'list' | 'tabular';
19
20
  }
20
- export interface BioProps extends Omit<BaseProps, 'numberOfRowsToStart' | 'isLazyLoad' | 'categories' | 'entriesToRemove' | 'isMediaTrained'> {
21
+ export interface BioProps extends Omit<BaseProps, 'numberOfRowsToStart' | 'isLazyLoad' | 'categories' | 'entriesToRemove' | 'ids' | 'isMediaTrained'> {
22
+ expertId?: string;
23
+ }
24
+ export interface InTheNewsProps extends Omit<BaseProps, 'categories' | 'entriesToRemove' | 'ids' | 'isMediaTrained' | 'numberOfRowsToStart' | 'isLazyLoad'> {
21
25
  expertId: string;
26
+ numberOfRowsToStart?: number;
27
+ isLazyLoad?: boolean;
22
28
  }
23
29
  //# sourceMappingURL=_types.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"_types.d.ts","sourceRoot":"","sources":["../../../source/feeds/experts/_types.ts"],"names":[],"mappings":"AAaA,MAAM,WAAW,SAAS;IAExB,KAAK,EAAE,MAAM,CAAC;IAEd,mBAAmB,EAAE,MAAM,CAAC;IAE5B,UAAU,CAAC,EAAE,MAAM,EAAE,CAAC;IAEtB,WAAW,CAAC,EAAE,OAAO,CAAC;IAEtB,cAAc,CAAC,EAAE,OAAO,CAAC;IAEzB,UAAU,EAAE,OAAO,CAAC;IAEpB,eAAe,CAAC,EAAE,MAAM,EAAE,CAAC;IAE3B,aAAa,CAAC,EAAE,CAAC,SAAS,EAAE,MAAM,KAAK,IAAI,CAAC;CAC7C;AAOD,MAAM,WAAW,SAAU,SAAQ,SAAS;IAE1C,qBAAqB,CAAC,EAAE,MAAM,CAAC;IAE/B,aAAa,CAAC,EAAE,OAAO,CAAC;IAExB,SAAS,CAAC,EAAE,OAAO,CAAC;IAEpB,QAAQ,CAAC,EAAE,OAAO,GAAG,MAAM,GAAG,SAAS,CAAC;CACzC;AAOD,MAAM,WAAW,SAAU,SAAQ,SAAS;IAE1C,QAAQ,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;CAC/B;AAOD,MAAM,WAAW,QACf,SAAQ,IAAI,CACV,SAAS,EACP,qBAAqB,GACrB,YAAY,GACZ,YAAY,GACZ,iBAAiB,GACjB,gBAAgB,CACnB;IAED,QAAQ,EAAE,MAAM,CAAC;CAClB"}
1
+ {"version":3,"file":"_types.d.ts","sourceRoot":"","sources":["../../../source/feeds/experts/_types.ts"],"names":[],"mappings":"AAaA,MAAM,WAAW,SAAS;IAExB,KAAK,EAAE,MAAM,CAAC;IAEd,mBAAmB,EAAE,MAAM,CAAC;IAE5B,UAAU,CAAC,EAAE,MAAM,EAAE,CAAC;IAEtB,WAAW,CAAC,EAAE,OAAO,CAAC;IAEtB,UAAU,EAAE,OAAO,CAAC;IAEpB,eAAe,CAAC,EAAE,MAAM,EAAE,CAAC;IAE3B,GAAG,CAAC,EAAE,MAAM,EAAE,CAAC;IAEf,cAAc,CAAC,EAAE,OAAO,CAAC;IAEzB,aAAa,CAAC,EAAE,CAAC,SAAS,EAAE,MAAM,KAAK,IAAI,CAAC;CAC7C;AAOD,MAAM,WAAW,SAAU,SAAQ,SAAS;IAE1C,qBAAqB,CAAC,EAAE,MAAM,CAAC;IAE/B,aAAa,CAAC,EAAE,OAAO,CAAC;IAExB,SAAS,CAAC,EAAE,OAAO,CAAC;IAEpB,QAAQ,CAAC,EAAE,OAAO,GAAG,MAAM,GAAG,SAAS,CAAC;CACzC;AAOD,MAAM,WAAW,SAAU,SAAQ,SAAS;IAE1C,QAAQ,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;CAC/B;AAOD,MAAM,WAAW,QACf,SAAQ,IAAI,CACV,SAAS,EACP,qBAAqB,GACrB,YAAY,GACZ,YAAY,GACZ,iBAAiB,GACjB,KAAK,GACL,gBAAgB,CACnB;IAED,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAQD,MAAM,WAAW,cACf,SAAQ,IAAI,CACV,SAAS,EACP,YAAY,GACZ,iBAAiB,GACjB,KAAK,GACL,gBAAgB,GAChB,qBAAqB,GACrB,YAAY,CACf;IAED,QAAQ,EAAE,MAAM,CAAC;IAEjB,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAE7B,UAAU,CAAC,EAAE,OAAO,CAAC;CACtB"}
@@ -1 +1 @@
1
- {"version":3,"file":"bio.d.ts","sourceRoot":"","sources":["../../../source/feeds/experts/bio.ts"],"names":[],"mappings":"AAmBA,OAAO,EAAE,KAAK,QAAQ,EAAE,MAAM,UAAU,CAAC;AACzC,OAAO,EAAE,KAAK,YAAY,EAAE,MAAM,cAAc,CAAC;AA8MjD,eAAO,MAAM,UAAU,GAAI,OAAO,QAAQ,KAAG,YAuD5C,CAAC"}
1
+ {"version":3,"file":"bio.d.ts","sourceRoot":"","sources":["../../../source/feeds/experts/bio.ts"],"names":[],"mappings":"AAmBA,OAAO,EAAE,KAAK,QAAQ,EAAE,MAAM,UAAU,CAAC;AACzC,OAAO,EAAE,KAAK,YAAY,EAAE,MAAM,cAAc,CAAC;AA8MjD,eAAO,MAAM,UAAU,GAAI,OAAO,QAAQ,KAAG,YAqE5C,CAAC"}
@@ -12,7 +12,7 @@ const createFetchProps = (token, expertId) => ({
12
12
  token,
13
13
  limit: 1,
14
14
  offset: 0,
15
- id: expertId
15
+ ids: [expertId]
16
16
  });
17
17
  const createSuccessAnnouncer = (expert) => {
18
18
  const fullName = buildFullName(expert);
@@ -110,23 +110,33 @@ const expertsBio = (props) => {
110
110
  "expert-bio-feed"
111
111
  );
112
112
  const container = containerBuilder.getElement();
113
+ if (!expertId) {
114
+ logError("invalid_request", "unknown");
115
+ const model2 = containerBuilder.build();
116
+ return {
117
+ element: model2.element,
118
+ styles: "",
119
+ events: {}
120
+ };
121
+ }
122
+ const validExpertId = expertId;
113
123
  const loading = new LoadingState({ isThemeDark });
114
124
  const state = new BioFeedState(loading.styles);
115
125
  const initialize = async () => {
116
126
  loading.show(container);
117
127
  try {
118
- const fetchProps = createFetchProps(token, expertId);
128
+ const fetchProps = createFetchProps(token, validExpertId);
119
129
  const variables = expertsFetchStrategy.composeApiVariables(fetchProps);
120
130
  const entries = await expertsFetchStrategy.fetchEntries(variables);
121
131
  loading.hide();
122
132
  if (!entries || entries.length === 0) {
123
- logError("not_found", expertId);
133
+ logError("not_found", validExpertId);
124
134
  return;
125
135
  }
126
136
  await renderSuccess(container, entries[0], state, isThemeDark);
127
137
  } catch (error) {
128
138
  loading.hide();
129
- logError("graphql_error", expertId, error);
139
+ logError("graphql_error", validExpertId, error);
130
140
  }
131
141
  };
132
142
  initialize();
@@ -1 +1 @@
1
- {"version":3,"file":"bio.js","sources":["../../../source/feeds/experts/bio.ts"],"sourcesContent":["/**\n * Expert Bio Feed (Refactored with Element Builder)\n *\n * Displays a single expert's profile with summary.\n * Uses element builder pattern for clean, declarative construction.\n *\n * @module feeds/experts/bio\n */\n\nimport { ElementBuilder } from '@universityofmaryland/web-builder-library';\nimport { person } from '@universityofmaryland/web-elements-library/composite';\nimport { LoadingState, Announcer } from '../../states';\nimport { expertsFetchStrategy } from '../../strategies/fetch/experts';\nimport {\n mapExpertToBioProps,\n buildFullName,\n} from '../../strategies/display/experts';\nimport { styles as styleUtilities } from '../../helpers';\nimport { type ExpertEntry } from 'types/data';\nimport { type BioProps } from './_types';\nimport { type ElementModel } from '../../_types';\n\n// ============================================================================\n// PURE HELPER FUNCTIONS\n// ============================================================================\n\n/**\n * Create base props for fetch strategy\n *\n * @param token - API authentication token\n * @param expertId - Expert ID to fetch\n * @returns Base props object for strategy's composeApiVariables\n */\nconst createFetchProps = (token: string, expertId: string) => ({\n token,\n limit: 1,\n offset: 0,\n id: expertId,\n});\n\n/**\n * Create accessibility announcer for loaded expert\n *\n * @param expert - Expert entry\n * @returns Announcer element model\n */\nconst createSuccessAnnouncer = (expert: ExpertEntry): Announcer => {\n const fullName = buildFullName(expert);\n const message = `Loaded profile for ${fullName}`;\n return new Announcer({ message });\n};\n\n// ============================================================================\n// STATE MANAGER CLASS\n// ============================================================================\n\n/**\n * Manages bio feed state and shadow DOM synchronization\n *\n * Encapsulates style accumulation and shadow DOM updates.\n * Provides immutable-style API for adding styles.\n */\nclass BioFeedState {\n private stylesArray: string[] = [];\n private shadowRoot: ShadowRoot | null = null;\n\n /**\n * Initialize state with initial styles\n *\n * @param initialStyles - Initial CSS styles\n */\n constructor(initialStyles: string) {\n this.stylesArray.push(initialStyles);\n }\n\n /**\n * Add styles to the accumulated styles\n *\n * @param styles - CSS styles to add\n */\n addStyles(styles: string): void {\n this.stylesArray.push(styles);\n }\n\n /**\n * Set shadow root reference for style updates\n *\n * @param shadow - Shadow root element\n */\n setShadowRoot(shadow: ShadowRoot): void {\n this.shadowRoot = shadow;\n }\n\n /**\n * Update shadow DOM styles\n *\n * @returns Promise that resolves when styles are updated\n */\n async updateShadowStyles(): Promise<void> {\n if (!this.shadowRoot) return;\n await styleUtilities.setShadowStyles({\n shadowRoot: this.shadowRoot,\n styles: this.getStyles(),\n });\n }\n\n /**\n * Get accumulated styles as single string\n *\n * @returns Combined CSS styles\n */\n getStyles(): string {\n return this.stylesArray.join('\\n');\n }\n\n /**\n * Get shadow root callback for events\n *\n * @returns Callback function for shadow root\n */\n getShadowCallback(): (shadow: ShadowRoot) => void {\n return (shadow) => this.setShadowRoot(shadow);\n }\n}\n\n// ============================================================================\n// RENDERING FUNCTIONS\n// ============================================================================\n\n/**\n * Render successful bio with expert data\n *\n * @param container - Container element to render into\n * @param expert - Expert entry data\n * @param state - State manager instance\n * @param isThemeDark - Dark theme flag\n * @returns Promise that resolves when rendering is complete\n */\nconst renderSuccess = async (\n container: HTMLElement,\n expert: ExpertEntry,\n state: BioFeedState,\n isThemeDark: boolean,\n): Promise<void> => {\n const bioProps = mapExpertToBioProps(expert, 'small', isThemeDark);\n const bioElement = person.bio.small(bioProps);\n const announcer = createSuccessAnnouncer(expert);\n const children = [bioElement.element, announcer.getElement()];\n\n children.forEach((child) => container.appendChild(child));\n\n state.addStyles(bioElement.styles);\n await state.updateShadowStyles();\n};\n\n/**\n * Error types for expert bio feed\n */\ntype BioErrorType = 'not_found' | 'graphql_error' | 'invalid_request';\n\n/**\n * Log error to console with specific warning message\n *\n * @param errorType - Type of error that occurred\n * @param expertId - Expert ID that was requested\n * @param error - Optional error object for GraphQL errors\n */\nconst logError = (\n errorType: BioErrorType,\n expertId: string,\n error?: any,\n): void => {\n switch (errorType) {\n case 'not_found':\n console.warn(\n `[Expert Bio Feed] No expert found with ID \"${expertId}\". ` +\n `Please verify the expert ID is correct and the expert exists in the system.`,\n );\n break;\n case 'graphql_error':\n console.warn(\n `[Expert Bio Feed] GraphQL error occurred while fetching expert \"${expertId}\". ` +\n `Check network connection and API availability.`,\n error,\n );\n break;\n case 'invalid_request':\n console.warn(\n `[Expert Bio Feed] Invalid request for expert \"${expertId}\". ` +\n `Ensure both data-token and data-id attributes are provided.`,\n );\n break;\n }\n};\n\n// ============================================================================\n// MAIN EXPORT\n// ============================================================================\n\n/**\n * Create an expert bio feed\n *\n * Fetches and displays a single expert's bio with summary.\n * Uses element builder pattern for clean construction.\n *\n * @param props - Feed configuration\n * @returns ElementModel with bio element, styles, and events\n *\n * @example\n * ```typescript\n * const bio = expertBio({\n * token: 'my-token',\n * expertId: 'john-doe',\n * });\n * ```\n *\n * @example\n * ```typescript\n * // With dark theme\n * const bio = expertBio({\n * token: 'my-token',\n * expertId: 'jane-smith',\n * isThemeDark: true,\n * });\n * ```\n */\nexport const expertsBio = (props: BioProps): ElementModel => {\n const { token, expertId, isThemeDark = false } = props;\n\n // Create container using ElementBuilder\n const containerBuilder = new ElementBuilder('div').withClassName(\n 'expert-bio-feed',\n );\n\n // Get element for manipulation (non-destructive)\n const container = containerBuilder.getElement();\n\n // Initialize state management\n const loading = new LoadingState({ isThemeDark });\n const state = new BioFeedState(loading.styles);\n\n /**\n * Fetch expert data and render\n */\n const initialize = async (): Promise<void> => {\n loading.show(container);\n\n try {\n const fetchProps = createFetchProps(token, expertId);\n const variables = expertsFetchStrategy.composeApiVariables(fetchProps);\n const entries = await expertsFetchStrategy.fetchEntries(variables);\n\n loading.hide();\n\n if (!entries || entries.length === 0) {\n logError('not_found', expertId);\n return;\n }\n\n await renderSuccess(container, entries[0], state, isThemeDark);\n } catch (error) {\n loading.hide();\n logError('graphql_error', expertId, error);\n }\n };\n\n // Start initialization\n initialize();\n\n // Build and return element model\n const model = containerBuilder.build();\n\n return {\n element: model.element,\n get styles() {\n return state.getStyles();\n },\n events: {\n callback: state.getShadowCallback(),\n },\n };\n};\n"],"names":["styleUtilities.setShadowStyles"],"mappings":"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"}
1
+ {"version":3,"file":"bio.js","sources":["../../../source/feeds/experts/bio.ts"],"sourcesContent":["/**\n * Expert Bio Feed (Refactored with Element Builder)\n *\n * Displays a single expert's profile with summary.\n * Uses element builder pattern for clean, declarative construction.\n *\n * @module feeds/experts/bio\n */\n\nimport { ElementBuilder } from '@universityofmaryland/web-builder-library';\nimport { person } from '@universityofmaryland/web-elements-library/composite';\nimport { LoadingState, Announcer } from '../../states';\nimport { expertsFetchStrategy } from '../../strategies/fetch/experts';\nimport {\n mapExpertToBioProps,\n buildFullName,\n} from '../../strategies/display/experts';\nimport { styles as styleUtilities } from '../../helpers';\nimport { type ExpertEntry } from 'types/data';\nimport { type BioProps } from './_types';\nimport { type ElementModel } from '../../_types';\n\n// ============================================================================\n// PURE HELPER FUNCTIONS\n// ============================================================================\n\n/**\n * Create base props for fetch strategy\n *\n * @param token - API authentication token\n * @param expertId - Expert ID to fetch\n * @returns Base props object for strategy's composeApiVariables\n */\nconst createFetchProps = (token: string, expertId: string) => ({\n token,\n limit: 1,\n offset: 0,\n ids: [expertId],\n});\n\n/**\n * Create accessibility announcer for loaded expert\n *\n * @param expert - Expert entry\n * @returns Announcer element model\n */\nconst createSuccessAnnouncer = (expert: ExpertEntry): Announcer => {\n const fullName = buildFullName(expert);\n const message = `Loaded profile for ${fullName}`;\n return new Announcer({ message });\n};\n\n// ============================================================================\n// STATE MANAGER CLASS\n// ============================================================================\n\n/**\n * Manages bio feed state and shadow DOM synchronization\n *\n * Encapsulates style accumulation and shadow DOM updates.\n * Provides immutable-style API for adding styles.\n */\nclass BioFeedState {\n private stylesArray: string[] = [];\n private shadowRoot: ShadowRoot | null = null;\n\n /**\n * Initialize state with initial styles\n *\n * @param initialStyles - Initial CSS styles\n */\n constructor(initialStyles: string) {\n this.stylesArray.push(initialStyles);\n }\n\n /**\n * Add styles to the accumulated styles\n *\n * @param styles - CSS styles to add\n */\n addStyles(styles: string): void {\n this.stylesArray.push(styles);\n }\n\n /**\n * Set shadow root reference for style updates\n *\n * @param shadow - Shadow root element\n */\n setShadowRoot(shadow: ShadowRoot): void {\n this.shadowRoot = shadow;\n }\n\n /**\n * Update shadow DOM styles\n *\n * @returns Promise that resolves when styles are updated\n */\n async updateShadowStyles(): Promise<void> {\n if (!this.shadowRoot) return;\n await styleUtilities.setShadowStyles({\n shadowRoot: this.shadowRoot,\n styles: this.getStyles(),\n });\n }\n\n /**\n * Get accumulated styles as single string\n *\n * @returns Combined CSS styles\n */\n getStyles(): string {\n return this.stylesArray.join('\\n');\n }\n\n /**\n * Get shadow root callback for events\n *\n * @returns Callback function for shadow root\n */\n getShadowCallback(): (shadow: ShadowRoot) => void {\n return (shadow) => this.setShadowRoot(shadow);\n }\n}\n\n// ============================================================================\n// RENDERING FUNCTIONS\n// ============================================================================\n\n/**\n * Render successful bio with expert data\n *\n * @param container - Container element to render into\n * @param expert - Expert entry data\n * @param state - State manager instance\n * @param isThemeDark - Dark theme flag\n * @returns Promise that resolves when rendering is complete\n */\nconst renderSuccess = async (\n container: HTMLElement,\n expert: ExpertEntry,\n state: BioFeedState,\n isThemeDark: boolean,\n): Promise<void> => {\n const bioProps = mapExpertToBioProps(expert, 'small', isThemeDark);\n const bioElement = person.bio.small(bioProps);\n const announcer = createSuccessAnnouncer(expert);\n const children = [bioElement.element, announcer.getElement()];\n\n children.forEach((child) => container.appendChild(child));\n\n state.addStyles(bioElement.styles);\n await state.updateShadowStyles();\n};\n\n/**\n * Error types for expert bio feed\n */\ntype BioErrorType = 'not_found' | 'graphql_error' | 'invalid_request';\n\n/**\n * Log error to console with specific warning message\n *\n * @param errorType - Type of error that occurred\n * @param expertId - Expert ID that was requested\n * @param error - Optional error object for GraphQL errors\n */\nconst logError = (\n errorType: BioErrorType,\n expertId: string,\n error?: any,\n): void => {\n switch (errorType) {\n case 'not_found':\n console.warn(\n `[Expert Bio Feed] No expert found with ID \"${expertId}\". ` +\n `Please verify the expert ID is correct and the expert exists in the system.`,\n );\n break;\n case 'graphql_error':\n console.warn(\n `[Expert Bio Feed] GraphQL error occurred while fetching expert \"${expertId}\". ` +\n `Check network connection and API availability.`,\n error,\n );\n break;\n case 'invalid_request':\n console.warn(\n `[Expert Bio Feed] Invalid request for expert \"${expertId}\". ` +\n `Ensure both data-token and data-id attributes are provided.`,\n );\n break;\n }\n};\n\n// ============================================================================\n// MAIN EXPORT\n// ============================================================================\n\n/**\n * Create an expert bio feed\n *\n * Fetches and displays a single expert's bio with summary.\n * Uses element builder pattern for clean construction.\n *\n * @param props - Feed configuration\n * @returns ElementModel with bio element, styles, and events\n *\n * @example\n * ```typescript\n * const bio = expertBio({\n * token: 'my-token',\n * expertId: 'john-doe',\n * });\n * ```\n *\n * @example\n * ```typescript\n * // With dark theme\n * const bio = expertBio({\n * token: 'my-token',\n * expertId: 'jane-smith',\n * isThemeDark: true,\n * });\n * ```\n */\nexport const expertsBio = (props: BioProps): ElementModel => {\n const { token, expertId, isThemeDark = false } = props;\n\n // Create container using ElementBuilder\n const containerBuilder = new ElementBuilder('div').withClassName(\n 'expert-bio-feed',\n );\n\n // Get element for manipulation (non-destructive)\n const container = containerBuilder.getElement();\n\n // Validate required expertId\n if (!expertId) {\n logError('invalid_request', 'unknown');\n const model = containerBuilder.build();\n return {\n element: model.element,\n styles: '',\n events: {},\n };\n }\n\n // Store validated expertId for use in async function\n const validExpertId = expertId;\n\n // Initialize state management\n const loading = new LoadingState({ isThemeDark });\n const state = new BioFeedState(loading.styles);\n\n /**\n * Fetch expert data and render\n */\n const initialize = async (): Promise<void> => {\n loading.show(container);\n\n try {\n const fetchProps = createFetchProps(token, validExpertId);\n const variables = expertsFetchStrategy.composeApiVariables(fetchProps);\n const entries = await expertsFetchStrategy.fetchEntries(variables);\n\n loading.hide();\n\n if (!entries || entries.length === 0) {\n logError('not_found', validExpertId);\n return;\n }\n\n await renderSuccess(container, entries[0], state, isThemeDark);\n } catch (error) {\n loading.hide();\n logError('graphql_error', validExpertId, error);\n }\n };\n\n // Start initialization\n initialize();\n\n // Build and return element model\n const model = containerBuilder.build();\n\n return {\n element: model.element,\n get styles() {\n return state.getStyles();\n },\n events: {\n callback: state.getShadowCallback(),\n },\n };\n};\n"],"names":["styleUtilities.setShadowStyles","model"],"mappings":"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"}
@@ -12,6 +12,7 @@ import "@universityofmaryland/web-utilities-library/network";
12
12
  import "../../strategies/fetch/events.js";
13
13
  import "../../strategies/fetch/news.js";
14
14
  import { expertsFetchStrategy } from "../../strategies/fetch/experts.js";
15
+ import "../../strategies/fetch/inTheNews.js";
15
16
  import { gridLayout, gridBorderLayout } from "../../strategies/layout/grid.js";
16
17
  import "@universityofmaryland/web-elements-library/layout";
17
18
  const expertsGrid = (props) => {
@@ -1 +1 @@
1
- {"version":3,"file":"grid.js","sources":["../../../source/feeds/experts/grid.ts"],"sourcesContent":["/**\n * Experts Grid Feed (Factory Pattern)\n *\n * Grid layout for expert profile entries using the feed factory pattern.\n * Uses person elements for displaying expert profiles in a multi-column grid.\n * Supports overlay cards with gridLayout or standard cards with gridGapLayout.\n *\n * @module feeds/experts/grid\n */\n\nimport { createBaseFeed } from 'factory';\nimport {\n expertsFetchStrategy,\n expertsDisplayStrategy,\n gridLayout,\n gridBorderLayout,\n} from 'strategies';\nimport { type GridProps } from './_types';\nimport { type ElementModel } from '../../_types';\n\n/**\n * Create an experts grid feed\n *\n * @param props - Feed configuration\n * @returns ElementModel with feed element and styles\n *\n * @example\n * ```typescript\n * // Standard grid with borders\n * const feed = expertsGrid({\n * token: 'my-token',\n * numberOfColumnsToShow: 3,\n * numberOfRowsToStart: 2,\n * isLazyLoad: true,\n * categories: ['computer-science', 'engineering'],\n * });\n *\n * // Overlay grid\n * const overlayFeed = expertsGrid({\n * token: 'my-token',\n * numberOfColumnsToShow: 4,\n * numberOfRowsToStart: 2,\n * isOverlay: true,\n * });\n *\n * document.body.appendChild(feed.element);\n * ```\n */\nexport const expertsGrid = (props: GridProps): ElementModel => {\n const { isOverlay = false } = props;\n\n return createBaseFeed({\n ...props,\n isOverlay,\n isAligned: !isOverlay,\n fetchStrategy: expertsFetchStrategy,\n displayStrategy: expertsDisplayStrategy,\n layoutStrategy: isOverlay ? gridLayout : gridBorderLayout,\n imageConfig: (entry) => ({\n imageUrl: entry.headshot?.[0]?.url || '',\n altText: entry.middleName\n ? `${entry.firstName} ${entry.middleName} ${entry.lastName}`\n : `${entry.firstName} ${entry.lastName}`,\n linkUrl: `https://umdrightnow.umd.edu/expert/${entry.slug}`,\n linkLabel: `View profile for ${entry.firstName} ${entry.lastName}`,\n }),\n });\n};\n"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAgDO,MAAM,cAAc,CAAC,UAAmC;AAC7D,QAAM,EAAE,YAAY,MAAA,IAAU;AAE9B,SAAO,eAAe;AAAA,IACpB,GAAG;AAAA,IACH;AAAA,IACA,WAAW,CAAC;AAAA,IACZ,eAAe;AAAA,IACf,iBAAiB;AAAA,IACjB,gBAAgB,YAAY,aAAa;AAAA,IACzC,aAAa,CAAC,WAAW;AAAA,MACvB,UAAU,MAAM,WAAW,CAAC,GAAG,OAAO;AAAA,MACtC,SAAS,MAAM,aACX,GAAG,MAAM,SAAS,IAAI,MAAM,UAAU,IAAI,MAAM,QAAQ,KACxD,GAAG,MAAM,SAAS,IAAI,MAAM,QAAQ;AAAA,MACxC,SAAS,sCAAsC,MAAM,IAAI;AAAA,MACzD,WAAW,oBAAoB,MAAM,SAAS,IAAI,MAAM,QAAQ;AAAA,IAAA;AAAA,EAClE,CACD;AACH;"}
1
+ {"version":3,"file":"grid.js","sources":["../../../source/feeds/experts/grid.ts"],"sourcesContent":["/**\n * Experts Grid Feed (Factory Pattern)\n *\n * Grid layout for expert profile entries using the feed factory pattern.\n * Uses person elements for displaying expert profiles in a multi-column grid.\n * Supports overlay cards with gridLayout or standard cards with gridGapLayout.\n *\n * @module feeds/experts/grid\n */\n\nimport { createBaseFeed } from 'factory';\nimport {\n expertsFetchStrategy,\n expertsDisplayStrategy,\n gridLayout,\n gridBorderLayout,\n} from 'strategies';\nimport { type GridProps } from './_types';\nimport { type ElementModel } from '../../_types';\n\n/**\n * Create an experts grid feed\n *\n * @param props - Feed configuration\n * @returns ElementModel with feed element and styles\n *\n * @example\n * ```typescript\n * // Standard grid with borders\n * const feed = expertsGrid({\n * token: 'my-token',\n * numberOfColumnsToShow: 3,\n * numberOfRowsToStart: 2,\n * isLazyLoad: true,\n * categories: ['computer-science', 'engineering'],\n * });\n *\n * // Overlay grid\n * const overlayFeed = expertsGrid({\n * token: 'my-token',\n * numberOfColumnsToShow: 4,\n * numberOfRowsToStart: 2,\n * isOverlay: true,\n * });\n *\n * document.body.appendChild(feed.element);\n * ```\n */\nexport const expertsGrid = (props: GridProps): ElementModel => {\n const { isOverlay = false } = props;\n\n return createBaseFeed({\n ...props,\n isOverlay,\n isAligned: !isOverlay,\n fetchStrategy: expertsFetchStrategy,\n displayStrategy: expertsDisplayStrategy,\n layoutStrategy: isOverlay ? gridLayout : gridBorderLayout,\n imageConfig: (entry) => ({\n imageUrl: entry.headshot?.[0]?.url || '',\n altText: entry.middleName\n ? `${entry.firstName} ${entry.middleName} ${entry.lastName}`\n : `${entry.firstName} ${entry.lastName}`,\n linkUrl: `https://umdrightnow.umd.edu/expert/${entry.slug}`,\n linkLabel: `View profile for ${entry.firstName} ${entry.lastName}`,\n }),\n });\n};\n"],"names":[],"mappings":";;;;;;;;;;;;;;;;;AAgDO,MAAM,cAAc,CAAC,UAAmC;AAC7D,QAAM,EAAE,YAAY,MAAA,IAAU;AAE9B,SAAO,eAAe;AAAA,IACpB,GAAG;AAAA,IACH;AAAA,IACA,WAAW,CAAC;AAAA,IACZ,eAAe;AAAA,IACf,iBAAiB;AAAA,IACjB,gBAAgB,YAAY,aAAa;AAAA,IACzC,aAAa,CAAC,WAAW;AAAA,MACvB,UAAU,MAAM,WAAW,CAAC,GAAG,OAAO;AAAA,MACtC,SAAS,MAAM,aACX,GAAG,MAAM,SAAS,IAAI,MAAM,UAAU,IAAI,MAAM,QAAQ,KACxD,GAAG,MAAM,SAAS,IAAI,MAAM,QAAQ;AAAA,MACxC,SAAS,sCAAsC,MAAM,IAAI;AAAA,MACzD,WAAW,oBAAoB,MAAM,SAAS,IAAI,MAAM,QAAQ;AAAA,IAAA;AAAA,EAClE,CACD;AACH;"}
@@ -0,0 +1,4 @@
1
+ import { InTheNewsProps } from './_types';
2
+ import { ElementModel } from '../../_types';
3
+ export declare const expertsInTheNews: (props: InTheNewsProps) => ElementModel;
4
+ //# sourceMappingURL=in-the-news.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"in-the-news.d.ts","sourceRoot":"","sources":["../../../source/feeds/experts/in-the-news.ts"],"names":[],"mappings":"AAkBA,OAAO,EAAE,KAAK,cAAc,EAAE,MAAM,UAAU,CAAC;AAC/C,OAAO,EAAE,KAAK,YAAY,EAAE,MAAM,cAAc,CAAC;AA8SjD,eAAO,MAAM,gBAAgB,GAAI,OAAO,cAAc,KAAG,YAqJxD,CAAC"}