@universityofmaryland/web-feeds-library 1.3.9-beta.0 → 1.3.9
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.
- package/dist/feeds/events/_types.d.ts +1 -1
- package/dist/feeds/events/_types.d.ts.map +1 -1
- package/dist/feeds/events/grid.d.ts.map +1 -1
- package/dist/feeds/events/grid.js +2 -11
- package/dist/feeds/events/grid.js.map +1 -1
- package/dist/feeds/events/grouped.d.ts.map +1 -1
- package/dist/feeds/events/grouped.js +2 -13
- package/dist/feeds/events/grouped.js.map +1 -1
- package/dist/feeds/events/image.d.ts +8 -0
- package/dist/feeds/events/image.d.ts.map +1 -0
- package/dist/feeds/events/image.js +17 -0
- package/dist/feeds/events/image.js.map +1 -0
- package/dist/feeds/events/list.d.ts.map +1 -1
- package/dist/feeds/events/list.js +2 -13
- package/dist/feeds/events/list.js.map +1 -1
- package/dist/strategies/fetch/events.d.ts.map +1 -1
- package/dist/strategies/fetch/events.js +5 -1
- package/dist/strategies/fetch/events.js.map +1 -1
- package/dist/types/core.d.ts +1 -0
- package/dist/types/core.d.ts.map +1 -1
- package/package.json +5 -5
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"_types.d.ts","sourceRoot":"","sources":["../../../source/feeds/events/_types.ts"],"names":[],"mappings":"AAAA,UAAU,SAAS;IACjB,GAAG,EAAE,MAAM,CAAC;IACZ,
|
|
1
|
+
{"version":3,"file":"_types.d.ts","sourceRoot":"","sources":["../../../source/feeds/events/_types.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"grid.d.ts","sourceRoot":"","sources":["../../../source/feeds/events/grid.ts"],"names":[],"mappings":"AAeA,OAAO,EAAE,KAAK,UAAU,EAAE,MAAM,UAAU,CAAC;
|
|
1
|
+
{"version":3,"file":"grid.d.ts","sourceRoot":"","sources":["../../../source/feeds/events/grid.ts"],"names":[],"mappings":"AAeA,OAAO,EAAE,KAAK,UAAU,EAAE,MAAM,UAAU,CAAC;AAE3C,OAAO,EAAE,KAAK,YAAY,EAAE,MAAM,cAAc,CAAC;AAqBjD,eAAO,MAAM,UAAU,GAAI,OAAO,UAAU,KAAG,YAQ3C,CAAC"}
|
|
@@ -14,23 +14,14 @@ import "../../strategies/fetch/experts.js";
|
|
|
14
14
|
import "../../strategies/fetch/inTheNews.js";
|
|
15
15
|
import { gridGapLayout } from "../../strategies/layout/grid.js";
|
|
16
16
|
import "@universityofmaryland/web-elements-library/layout";
|
|
17
|
+
import { createEventImageConfig } from "./image.js";
|
|
17
18
|
const eventsGrid = (props) => createBaseFeed({
|
|
18
19
|
...props,
|
|
19
20
|
enableCategoryFallback: true,
|
|
20
21
|
fetchStrategy: eventsFetchStrategy,
|
|
21
22
|
displayStrategy: eventsDisplayStrategy,
|
|
22
23
|
layoutStrategy: gridGapLayout,
|
|
23
|
-
imageConfig:
|
|
24
|
-
const imageUrl = entry.image?.[0]?.url;
|
|
25
|
-
const altText = entry.image?.[0]?.altText;
|
|
26
|
-
if (!imageUrl || !altText) return null;
|
|
27
|
-
return {
|
|
28
|
-
imageUrl,
|
|
29
|
-
altText,
|
|
30
|
-
linkUrl: entry.url,
|
|
31
|
-
linkLabel: "University of Maryland Event"
|
|
32
|
-
};
|
|
33
|
-
}
|
|
24
|
+
imageConfig: createEventImageConfig
|
|
34
25
|
});
|
|
35
26
|
export {
|
|
36
27
|
eventsGrid
|
|
@@ -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:
|
|
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 { createEventImageConfig } from './image';\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: createEventImageConfig,\n });\n"],"names":[],"mappings":";;;;;;;;;;;;;;;;;AAsCO,MAAM,aAAa,CAAC,UACzB,eAAe;AAAA,EACb,GAAG;AAAA,EACH,wBAAwB;AAAA,EACxB,eAAe;AAAA,EACf,iBAAiB;AAAA,EACjB,gBAAgB;AAAA,EAChB,aAAa;AACf,CAAC;"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"grouped.d.ts","sourceRoot":"","sources":["../../../source/feeds/events/grouped.ts"],"names":[],"mappings":"AA2BA,OAAO,EAAE,KAAK,SAAS,EAAE,MAAM,UAAU,CAAC;
|
|
1
|
+
{"version":3,"file":"grouped.d.ts","sourceRoot":"","sources":["../../../source/feeds/events/grouped.ts"],"names":[],"mappings":"AA2BA,OAAO,EAAE,KAAK,SAAS,EAAE,MAAM,UAAU,CAAC;AAE1C,OAAO,EAAE,KAAK,YAAY,EAAE,MAAM,cAAc,CAAC;AAwbjD,eAAO,MAAM,aAAa,GAAI,OAAO,SAAS,KAAG,YA+HhD,CAAC"}
|
|
@@ -16,6 +16,7 @@ import "@universityofmaryland/web-elements-library/layout";
|
|
|
16
16
|
import { dispatch, eventNames } from "../../helpers/events/index.js";
|
|
17
17
|
import { groupEventsByDate } from "../../helpers/grouping/events.js";
|
|
18
18
|
import { setShadowStyles } from "../../helpers/styles/shadow.js";
|
|
19
|
+
import { createEventImageConfig } from "./image.js";
|
|
19
20
|
const createFetchProps = (props, offset) => ({
|
|
20
21
|
token: props.token,
|
|
21
22
|
categories: props.categories,
|
|
@@ -23,19 +24,7 @@ const createFetchProps = (props, offset) => ({
|
|
|
23
24
|
numberOfRowsToStart: props.numberOfRowsToStart,
|
|
24
25
|
getOffset: () => offset
|
|
25
26
|
});
|
|
26
|
-
const createImageConfig = (entry) =>
|
|
27
|
-
const imageUrl = entry.image?.[0]?.url;
|
|
28
|
-
const altText = entry.image?.[0]?.altText;
|
|
29
|
-
if (!imageUrl || !altText) {
|
|
30
|
-
return null;
|
|
31
|
-
}
|
|
32
|
-
return {
|
|
33
|
-
imageUrl,
|
|
34
|
-
altText,
|
|
35
|
-
linkUrl: entry.url,
|
|
36
|
-
linkLabel: "University of Maryland Event"
|
|
37
|
-
};
|
|
38
|
-
};
|
|
27
|
+
const createImageConfig = (entry) => createEventImageConfig(entry);
|
|
39
28
|
const createAnnouncerMessage = (count, total, isLazyLoad) => {
|
|
40
29
|
return isLazyLoad ? `Showing ${count} of ${total} events` : `Showing ${count} events`;
|
|
41
30
|
};
|
|
@@ -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 { isExternalUrl } from '@universityofmaryland/web-utilities-library/network';\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 const imageUrl = entry.image?.[0]?.url;\n const altText = entry.image?.[0]?.altText;\n\n if (!imageUrl || !altText) {\n return null;\n }\n\n return {\n imageUrl: imageUrl,\n altText: altText,\n linkUrl: entry.url,\n linkLabel: 'University of Maryland Event',\n };\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 const openInNewTab = isExternalUrl(entry.url);\n const imageData = createImageConfig(entry);\n const image =\n imageData && imageData.imageUrl && imageData.altText\n ? createImageOrLinkedImage({ ...imageData, openInNewTab })\n : null;\n\n return card.list({\n headline: createTextWithLink({ text: entry.title, url: entry.url, openInNewTab }),\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: image,\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-of-type)`]: {\n paddingBottom: 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: `none`,\n },\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 },\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 isThemeDark,\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 { isExternalUrl } from '@universityofmaryland/web-utilities-library/network';\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 { createEventImageConfig } from './image';\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) => createEventImageConfig(entry);\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 const openInNewTab = isExternalUrl(entry.url);\n const imageData = createImageConfig(entry);\n const image =\n imageData && imageData.imageUrl && imageData.altText\n ? createImageOrLinkedImage({ ...imageData, openInNewTab })\n : null;\n\n return card.list({\n headline: createTextWithLink({ text: entry.title, url: entry.url, openInNewTab }),\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: image,\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-of-type)`]: {\n paddingBottom: 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: `none`,\n },\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 },\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 isThemeDark,\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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"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { EventEntry } from '../../types/data';
|
|
2
|
+
export declare const createEventImageConfig: (entry: Pick<EventEntry, "image" | "url">) => {
|
|
3
|
+
imageUrl: string;
|
|
4
|
+
altText: string;
|
|
5
|
+
linkUrl: string;
|
|
6
|
+
linkLabel: string;
|
|
7
|
+
} | null;
|
|
8
|
+
//# sourceMappingURL=image.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"image.d.ts","sourceRoot":"","sources":["../../../source/feeds/events/image.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,UAAU,EAAE,MAAM,YAAY,CAAC;AAE7C,eAAO,MAAM,sBAAsB,GACjC,OAAO,IAAI,CAAC,UAAU,EAAE,OAAO,GAAG,KAAK,CAAC;;;;;QAezC,CAAC"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
const createEventImageConfig = (entry) => {
|
|
2
|
+
const imageUrl = entry.image?.[0]?.url;
|
|
3
|
+
const altText = entry.image?.[0]?.alt;
|
|
4
|
+
if (!imageUrl || !altText) {
|
|
5
|
+
return null;
|
|
6
|
+
}
|
|
7
|
+
return {
|
|
8
|
+
imageUrl,
|
|
9
|
+
altText,
|
|
10
|
+
linkUrl: entry.url,
|
|
11
|
+
linkLabel: "University of Maryland Event"
|
|
12
|
+
};
|
|
13
|
+
};
|
|
14
|
+
export {
|
|
15
|
+
createEventImageConfig
|
|
16
|
+
};
|
|
17
|
+
//# sourceMappingURL=image.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"image.js","sources":["../../../source/feeds/events/image.ts"],"sourcesContent":["import { type EventEntry } from 'types/data';\n\nexport const createEventImageConfig = (\n entry: Pick<EventEntry, 'image' | 'url'>,\n) => {\n const imageUrl = entry.image?.[0]?.url;\n const altText = entry.image?.[0]?.alt;\n\n if (!imageUrl || !altText) {\n return null;\n }\n\n return {\n imageUrl,\n altText,\n linkUrl: entry.url,\n linkLabel: 'University of Maryland Event',\n };\n};\n"],"names":[],"mappings":"AAEO,MAAM,yBAAyB,CACpC,UACG;AACH,QAAM,WAAW,MAAM,QAAQ,CAAC,GAAG;AACnC,QAAM,UAAU,MAAM,QAAQ,CAAC,GAAG;AAElC,MAAI,CAAC,YAAY,CAAC,SAAS;AACzB,WAAO;AAAA,EACT;AAEA,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA,SAAS,MAAM;AAAA,IACf,WAAW;AAAA,EAAA;AAEf;"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"list.d.ts","sourceRoot":"","sources":["../../../source/feeds/events/list.ts"],"names":[],"mappings":"AAeA,OAAO,EAAE,KAAK,SAAS,EAAE,MAAM,UAAU,CAAC;
|
|
1
|
+
{"version":3,"file":"list.d.ts","sourceRoot":"","sources":["../../../source/feeds/events/list.ts"],"names":[],"mappings":"AAeA,OAAO,EAAE,KAAK,SAAS,EAAE,MAAM,UAAU,CAAC;AAE1C,OAAO,EAAE,KAAK,YAAY,EAAE,MAAM,cAAc,CAAC;AAoBjD,eAAO,MAAM,UAAU,GAAI,OAAO,SAAS,KAAG,YAS1C,CAAC"}
|
|
@@ -14,6 +14,7 @@ import "../../strategies/fetch/experts.js";
|
|
|
14
14
|
import "../../strategies/fetch/inTheNews.js";
|
|
15
15
|
import { stackedLayout } from "../../strategies/layout/grid.js";
|
|
16
16
|
import "@universityofmaryland/web-elements-library/layout";
|
|
17
|
+
import { createEventImageConfig } from "./image.js";
|
|
17
18
|
const eventsList = (props) => createBaseFeed({
|
|
18
19
|
...props,
|
|
19
20
|
enableCategoryFallback: true,
|
|
@@ -21,19 +22,7 @@ const eventsList = (props) => createBaseFeed({
|
|
|
21
22
|
fetchStrategy: eventsFetchStrategy,
|
|
22
23
|
displayStrategy: eventsDisplayStrategy,
|
|
23
24
|
layoutStrategy: stackedLayout,
|
|
24
|
-
imageConfig:
|
|
25
|
-
const imageUrl = entry.image?.[0]?.url;
|
|
26
|
-
const altText = entry.image?.[0]?.altText;
|
|
27
|
-
if (!imageUrl || !altText) {
|
|
28
|
-
return null;
|
|
29
|
-
}
|
|
30
|
-
return {
|
|
31
|
-
imageUrl,
|
|
32
|
-
altText,
|
|
33
|
-
linkUrl: entry.url,
|
|
34
|
-
linkLabel: "University of Maryland Event"
|
|
35
|
-
};
|
|
36
|
-
}
|
|
25
|
+
imageConfig: createEventImageConfig
|
|
37
26
|
});
|
|
38
27
|
export {
|
|
39
28
|
eventsList
|
|
@@ -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:
|
|
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 { createEventImageConfig } from './image';\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: createEventImageConfig,\n });\n"],"names":[],"mappings":";;;;;;;;;;;;;;;;;AAqCO,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;AACf,CAAC;"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"events.d.ts","sourceRoot":"","sources":["../../../source/strategies/fetch/events.ts"],"names":[],"mappings":"AASA,OAAO,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;
|
|
1
|
+
{"version":3,"file":"events.d.ts","sourceRoot":"","sources":["../../../source/strategies/fetch/events.ts"],"names":[],"mappings":"AASA,OAAO,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAmJxC,eAAO,MAAM,kBAAkB,QAA0B,CAAC;AAC1D,eAAO,MAAM,YAAY,QAAqB,CAAC;AAM/C,eAAO,MAAM,oBAAoB,0HAOhC,CAAC;AAMF,eAAO,MAAM,mBAAmB,QAc/B,CAAC;AAqDF,iBAAe,kBAAkB,CAC/B,WAAW,EAAE,MAAM,EAAE,EACrB,KAAK,CAAC,EAAE,MAAM,GACb,OAAO,CAAC,MAAM,EAAE,GAAG,IAAI,CAAC,CAkB1B;AAED,eAAO,MAAM,mBAAmB;;;;;CAG/B,CAAC;AAyCF,eAAO,MAAM,wBAAwB;;;;;CAGpC,CAAC"}
|
|
@@ -27,7 +27,7 @@ function generateFragments() {
|
|
|
27
27
|
summary: commonRichTextTwo
|
|
28
28
|
image: commonAssetHeroImageSingle {
|
|
29
29
|
url
|
|
30
|
-
|
|
30
|
+
alt
|
|
31
31
|
}
|
|
32
32
|
location: categoriesCampusBuildingSingle {
|
|
33
33
|
title
|
|
@@ -70,6 +70,10 @@ function generateSliderFragments() {
|
|
|
70
70
|
fragment EventSliderFields_${cal} on ${cal}_Event {
|
|
71
71
|
title
|
|
72
72
|
url
|
|
73
|
+
image: commonAssetHeroImageSingle {
|
|
74
|
+
url
|
|
75
|
+
alt
|
|
76
|
+
}
|
|
73
77
|
startMonth: startDate @formatDateTime(format: "M")
|
|
74
78
|
startDay: startDate @formatDateTime(format: "d")
|
|
75
79
|
endMonth: endDate @formatDateTime(format: "M")
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"events.js","sources":["../../../source/strategies/fetch/events.ts"],"sourcesContent":["/**\n * Events Fetch Strategy\n *\n * Strategy for fetching event data from the UMD Calendar GraphQL API.\n *\n * @module strategies/fetch/events\n */\n\nimport { createGraphQLFetchStrategy } from './graphql';\nimport { EventEntry } from 'types/data';\nimport { fetchGraphQL } from '@universityofmaryland/web-utilities-library/network';\n\n/**\n * Calendar types available in the UMD Calendar system\n */\nconst CALENDARS = ['communications', 'submission'] as const;\n\n/**\n * Generate GraphQL fragments for all calendar types\n * Creates type-specific fragments to avoid interface limitations\n */\nfunction generateFragments() {\n return CALENDARS.map(\n (cal) => `\n fragment EventBasicFields_${cal} on ${cal}_Event {\n id\n title\n url\n }\n\n fragment EventDateFields_${cal} on ${cal}_Event {\n startDayOfWeek: startDate @formatDateTime(format: \"D\")\n startMonth: startDate @formatDateTime(format: \"M\")\n startDay: startDate @formatDateTime(format: \"d\")\n startStamp: startDate @formatDateTime(format: \"Y-m-d\")\n startTime: startDate @formatDateTime(format: \"g:ia\")\n endDayOfWeek: endDate @formatDateTime(format: \"D\")\n endMonth: endDate @formatDateTime(format: \"M\")\n endDay: endDate @formatDateTime(format: \"d\")\n endTime: endDate @formatDateTime(format: \"g:ia\")\n allDay\n }\n\n fragment EventContentFields_${cal} on ${cal}_Event {\n summary: commonRichTextTwo\n image: commonAssetHeroImageSingle {\n url\n altText: commonPlainTextTwo\n }\n location: categoriesCampusBuildingSingle {\n title\n }\n }\n\n fragment EventCategoryFields_${cal} on ${cal}_Event {\n categories: categoriesEventAudienceMultiple {\n id\n title\n }\n }\n `,\n ).join('\\n');\n}\n\n/**\n * Generate inline fragment spreads for all calendar types\n * Used in the main query to apply fragments to each calendar type\n */\nfunction generateInlineSpreads() {\n return CALENDARS.map(\n (cal) => `\n ... on ${cal}_Event {\n ...EventBasicFields_${cal}\n ...EventDateFields_${cal}\n ...EventContentFields_${cal}\n ...EventCategoryFields_${cal}\n }\n `,\n ).join('\\n');\n}\n\n/**\n * Generate inline fragment spreads for slider queries\n * Minimal fields for carousel displays\n */\nfunction generateSliderSpreads() {\n return CALENDARS.map(\n (cal) => `\n ... on ${cal}_Event {\n ...EventSliderFields_${cal}\n }\n `,\n ).join('\\n');\n}\n\n/**\n * Generate slider-specific fragments\n */\nfunction generateSliderFragments() {\n return CALENDARS.map(\n (cal) => `\n fragment EventSliderFields_${cal} on ${cal}_Event {\n title\n url\n startMonth: startDate @formatDateTime(format: \"M\")\n startDay: startDate @formatDateTime(format: \"d\")\n endMonth: endDate @formatDateTime(format: \"M\")\n endDay: endDate @formatDateTime(format: \"d\")\n }\n `,\n ).join('\\n');\n}\n\n/**\n * GraphQL queries for events\n */\nconst buildEventsCountQuery = (\n dateFilter: 'startsAfterOrAt' | 'rangeStart' = 'startsAfterOrAt',\n) => `\n query getEventsCount($startDate: String!, $related: [QueryArgument]) {\n count: solspace_calendar {\n events(relatedTo: $related, loadOccurrences: true, ${dateFilter}: $startDate) {\n ... on communications_Event {\n id\n }\n ... on submission_Event {\n id\n }\n }\n }\n }\n`;\n\nconst buildEventsQuery = (\n dateFilter: 'startsAfterOrAt' | 'rangeStart' = 'startsAfterOrAt',\n) => `\n query getEvents($startDate: String!, $related: [QueryArgument], $limit: Int, $offset: Int) {\n entries: solspace_calendar {\n events(\n relatedTo: $related\n loadOccurrences: true\n ${dateFilter}: $startDate\n limit: $limit\n offset: $offset\n ) {\n ${generateInlineSpreads()}\n }\n }\n }\n ${generateFragments()}\n`;\n\nexport const EVENTS_COUNT_QUERY = buildEventsCountQuery();\nexport const EVENTS_QUERY = buildEventsQuery();\n\n/**\n * Query for fetching category names by IDs\n * Queries the categories table directly\n */\nexport const CATEGORY_NAMES_QUERY = `\n query getCategoryNames($ids: [QueryArgument]!) {\n categories(id: $ids) {\n id\n title\n }\n }\n`;\n\n/**\n * Slider-specific query with minimal fields\n * Used by events slider for carousel displays\n */\nexport const EVENTS_SLIDER_QUERY = `\n query getEvents($startDate: String!, $related: [QueryArgument]) {\n entries: solspace_calendar {\n events(\n relatedTo: $related\n loadOccurrences: true\n startsAfterOrAt: $startDate\n limit: 12\n ) {\n ${generateSliderSpreads()}\n }\n }\n }\n ${generateSliderFragments()}\n`;\n\n/**\n * Events fetch strategy\n *\n * Fetches event data from the UMD Calendar GraphQL API.\n * Handles date filtering, category filtering, and pagination.\n *\n * @example\n * ```typescript\n * const feed = createBaseFeed({\n * token: 'my-token',\n * fetchStrategy: eventsFetchStrategy,\n * // ...\n * });\n * ```\n */\nconst baseFetchStrategy = createGraphQLFetchStrategy<EventEntry>({\n endpoint: 'https://calendar.umd.edu/graphql',\n\n queries: {\n entries: EVENTS_QUERY,\n count: EVENTS_COUNT_QUERY,\n },\n\n transformResponse: (data) => {\n if (!data || !data.data || !data.data.entries) {\n return null;\n }\n return data.data.entries.events || null;\n },\n\n transformCount: (data) => {\n if (!data || !data.data || !data.data.count) {\n return 0;\n }\n return data.data.count.events?.length || 0;\n },\n\n composeVariables: (baseVariables) => {\n const { categories, ...rest } = baseVariables;\n\n return {\n ...rest,\n related: categories,\n startDate: new Date().toDateString(),\n };\n },\n});\n\n/**\n * Fetch category names by their IDs\n */\nasync function fetchCategoryNames(\n categoryIds: string[],\n token?: string,\n): Promise<string[] | null> {\n try {\n const response = await fetchGraphQL({\n url: 'https://calendar.umd.edu/graphql',\n query: CATEGORY_NAMES_QUERY,\n token: token || '',\n variables: { ids: categoryIds },\n });\n\n if (!response || !response.data || !response.data.categories) {\n return null;\n }\n\n return response.data.categories.map((category: any) => category.title);\n } catch (error) {\n console.error('Fetch category names error:', error);\n return null;\n }\n}\n\nexport const eventsFetchStrategy = {\n ...baseFetchStrategy,\n fetchCategoryNames,\n};\n\n/**\n * Events fetch strategy for range queries\n *\n * Uses rangeStart filter instead of startsAfterOrAt.\n * Used for grouped event displays.\n */\nconst baseFetchStrategyRange = createGraphQLFetchStrategy<EventEntry>({\n endpoint: 'https://calendar.umd.edu/graphql',\n\n queries: {\n entries: buildEventsQuery('rangeStart'),\n count: buildEventsCountQuery('rangeStart'),\n },\n\n transformResponse: (data) => {\n if (!data || !data.data || !data.data.entries) {\n return null;\n }\n return data.data.entries.events || null;\n },\n\n transformCount: (data) => {\n if (!data || !data.data || !data.data.count) {\n return 0;\n }\n return data.data.count.events?.length || 0;\n },\n\n composeVariables: (baseVariables) => {\n const { categories, ...rest } = baseVariables;\n\n return {\n ...rest,\n related: categories,\n startDate: new Date().toDateString(),\n };\n },\n});\n\nexport const eventsFetchStrategyRange = {\n ...baseFetchStrategyRange,\n fetchCategoryNames,\n};\n"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"events.js","sources":["../../../source/strategies/fetch/events.ts"],"sourcesContent":["/**\n * Events Fetch Strategy\n *\n * Strategy for fetching event data from the UMD Calendar GraphQL API.\n *\n * @module strategies/fetch/events\n */\n\nimport { createGraphQLFetchStrategy } from './graphql';\nimport { EventEntry } from 'types/data';\nimport { fetchGraphQL } from '@universityofmaryland/web-utilities-library/network';\n\n/**\n * Calendar types available in the UMD Calendar system\n */\nconst CALENDARS = ['communications', 'submission'] as const;\n\n/**\n * Generate GraphQL fragments for all calendar types\n * Creates type-specific fragments to avoid interface limitations\n */\nfunction generateFragments() {\n return CALENDARS.map(\n (cal) => `\n fragment EventBasicFields_${cal} on ${cal}_Event {\n id\n title\n url\n }\n\n fragment EventDateFields_${cal} on ${cal}_Event {\n startDayOfWeek: startDate @formatDateTime(format: \"D\")\n startMonth: startDate @formatDateTime(format: \"M\")\n startDay: startDate @formatDateTime(format: \"d\")\n startStamp: startDate @formatDateTime(format: \"Y-m-d\")\n startTime: startDate @formatDateTime(format: \"g:ia\")\n endDayOfWeek: endDate @formatDateTime(format: \"D\")\n endMonth: endDate @formatDateTime(format: \"M\")\n endDay: endDate @formatDateTime(format: \"d\")\n endTime: endDate @formatDateTime(format: \"g:ia\")\n allDay\n }\n\n fragment EventContentFields_${cal} on ${cal}_Event {\n summary: commonRichTextTwo\n image: commonAssetHeroImageSingle {\n url\n alt\n }\n location: categoriesCampusBuildingSingle {\n title\n }\n }\n\n fragment EventCategoryFields_${cal} on ${cal}_Event {\n categories: categoriesEventAudienceMultiple {\n id\n title\n }\n }\n `,\n ).join('\\n');\n}\n\n/**\n * Generate inline fragment spreads for all calendar types\n * Used in the main query to apply fragments to each calendar type\n */\nfunction generateInlineSpreads() {\n return CALENDARS.map(\n (cal) => `\n ... on ${cal}_Event {\n ...EventBasicFields_${cal}\n ...EventDateFields_${cal}\n ...EventContentFields_${cal}\n ...EventCategoryFields_${cal}\n }\n `,\n ).join('\\n');\n}\n\n/**\n * Generate inline fragment spreads for slider queries\n * Minimal fields for carousel displays\n */\nfunction generateSliderSpreads() {\n return CALENDARS.map(\n (cal) => `\n ... on ${cal}_Event {\n ...EventSliderFields_${cal}\n }\n `,\n ).join('\\n');\n}\n\n/**\n * Generate slider-specific fragments\n */\nfunction generateSliderFragments() {\n return CALENDARS.map(\n (cal) => `\n fragment EventSliderFields_${cal} on ${cal}_Event {\n title\n url\n image: commonAssetHeroImageSingle {\n url\n alt\n }\n startMonth: startDate @formatDateTime(format: \"M\")\n startDay: startDate @formatDateTime(format: \"d\")\n endMonth: endDate @formatDateTime(format: \"M\")\n endDay: endDate @formatDateTime(format: \"d\")\n }\n `,\n ).join('\\n');\n}\n\n/**\n * GraphQL queries for events\n */\nconst buildEventsCountQuery = (\n dateFilter: 'startsAfterOrAt' | 'rangeStart' = 'startsAfterOrAt',\n) => `\n query getEventsCount($startDate: String!, $related: [QueryArgument]) {\n count: solspace_calendar {\n events(relatedTo: $related, loadOccurrences: true, ${dateFilter}: $startDate) {\n ... on communications_Event {\n id\n }\n ... on submission_Event {\n id\n }\n }\n }\n }\n`;\n\nconst buildEventsQuery = (\n dateFilter: 'startsAfterOrAt' | 'rangeStart' = 'startsAfterOrAt',\n) => `\n query getEvents($startDate: String!, $related: [QueryArgument], $limit: Int, $offset: Int) {\n entries: solspace_calendar {\n events(\n relatedTo: $related\n loadOccurrences: true\n ${dateFilter}: $startDate\n limit: $limit\n offset: $offset\n ) {\n ${generateInlineSpreads()}\n }\n }\n }\n ${generateFragments()}\n`;\n\nexport const EVENTS_COUNT_QUERY = buildEventsCountQuery();\nexport const EVENTS_QUERY = buildEventsQuery();\n\n/**\n * Query for fetching category names by IDs\n * Queries the categories table directly\n */\nexport const CATEGORY_NAMES_QUERY = `\n query getCategoryNames($ids: [QueryArgument]!) {\n categories(id: $ids) {\n id\n title\n }\n }\n`;\n\n/**\n * Slider-specific query with minimal fields\n * Used by events slider for carousel displays\n */\nexport const EVENTS_SLIDER_QUERY = `\n query getEvents($startDate: String!, $related: [QueryArgument]) {\n entries: solspace_calendar {\n events(\n relatedTo: $related\n loadOccurrences: true\n startsAfterOrAt: $startDate\n limit: 12\n ) {\n ${generateSliderSpreads()}\n }\n }\n }\n ${generateSliderFragments()}\n`;\n\n/**\n * Events fetch strategy\n *\n * Fetches event data from the UMD Calendar GraphQL API.\n * Handles date filtering, category filtering, and pagination.\n *\n * @example\n * ```typescript\n * const feed = createBaseFeed({\n * token: 'my-token',\n * fetchStrategy: eventsFetchStrategy,\n * // ...\n * });\n * ```\n */\nconst baseFetchStrategy = createGraphQLFetchStrategy<EventEntry>({\n endpoint: 'https://calendar.umd.edu/graphql',\n\n queries: {\n entries: EVENTS_QUERY,\n count: EVENTS_COUNT_QUERY,\n },\n\n transformResponse: (data) => {\n if (!data || !data.data || !data.data.entries) {\n return null;\n }\n return data.data.entries.events || null;\n },\n\n transformCount: (data) => {\n if (!data || !data.data || !data.data.count) {\n return 0;\n }\n return data.data.count.events?.length || 0;\n },\n\n composeVariables: (baseVariables) => {\n const { categories, ...rest } = baseVariables;\n\n return {\n ...rest,\n related: categories,\n startDate: new Date().toDateString(),\n };\n },\n});\n\n/**\n * Fetch category names by their IDs\n */\nasync function fetchCategoryNames(\n categoryIds: string[],\n token?: string,\n): Promise<string[] | null> {\n try {\n const response = await fetchGraphQL({\n url: 'https://calendar.umd.edu/graphql',\n query: CATEGORY_NAMES_QUERY,\n token: token || '',\n variables: { ids: categoryIds },\n });\n\n if (!response || !response.data || !response.data.categories) {\n return null;\n }\n\n return response.data.categories.map((category: any) => category.title);\n } catch (error) {\n console.error('Fetch category names error:', error);\n return null;\n }\n}\n\nexport const eventsFetchStrategy = {\n ...baseFetchStrategy,\n fetchCategoryNames,\n};\n\n/**\n * Events fetch strategy for range queries\n *\n * Uses rangeStart filter instead of startsAfterOrAt.\n * Used for grouped event displays.\n */\nconst baseFetchStrategyRange = createGraphQLFetchStrategy<EventEntry>({\n endpoint: 'https://calendar.umd.edu/graphql',\n\n queries: {\n entries: buildEventsQuery('rangeStart'),\n count: buildEventsCountQuery('rangeStart'),\n },\n\n transformResponse: (data) => {\n if (!data || !data.data || !data.data.entries) {\n return null;\n }\n return data.data.entries.events || null;\n },\n\n transformCount: (data) => {\n if (!data || !data.data || !data.data.count) {\n return 0;\n }\n return data.data.count.events?.length || 0;\n },\n\n composeVariables: (baseVariables) => {\n const { categories, ...rest } = baseVariables;\n\n return {\n ...rest,\n related: categories,\n startDate: new Date().toDateString(),\n };\n },\n});\n\nexport const eventsFetchStrategyRange = {\n ...baseFetchStrategyRange,\n fetchCategoryNames,\n};\n"],"names":[],"mappings":"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"}
|
package/dist/types/core.d.ts
CHANGED
package/dist/types/core.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"core.d.ts","sourceRoot":"","sources":["../../source/types/core.ts"],"names":[],"mappings":"AAiBA,MAAM,WAAW,YAAY,CAAC,CAAC,GAAG,WAAW;IAE3C,OAAO,EAAE,CAAC,CAAC;IAEX,MAAM,EAAE,MAAM,CAAC;IAEf,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC;CACnC;AAOD,MAAM,WAAW,KAAK;IAEpB,GAAG,EAAE,MAAM,CAAC;IAEZ,OAAO,CAAC,EAAE,MAAM,CAAC;IAEjB,EAAE,CAAC,EAAE,MAAM,CAAC;CACb;AAOD,MAAM,WAAW,QAAQ;IAEvB,EAAE,CAAC,EAAE,MAAM,CAAC;IAEZ,KAAK,EAAE,MAAM,CAAC;IAEd,GAAG,EAAE,MAAM,CAAC;CACb;AAQD,MAAM,WAAW,SAAS;IAExB,EAAE,EAAE,MAAM,GAAG,MAAM,CAAC;IAEpB,KAAK,EAAE,MAAM,CAAC;IAEd,GAAG,EAAE,MAAM,CAAC;IAEZ,IAAI,CAAC,EAAE,MAAM,CAAC;IAEd,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAOD,MAAM,WAAW,UAAW,SAAQ,SAAS;IAE3C,KAAK,EAAE,KAAK,EAAE,CAAC;CAChB;AAOD,MAAM,WAAW,gBAAiB,SAAQ,SAAS;IAEjD,UAAU,CAAC,EAAE,QAAQ,EAAE,CAAC;CACzB;AAOD,MAAM,WAAW,UAAW,SAAQ,SAAS;IAE3C,IAAI,EAAE,MAAM,CAAC;IAEb,aAAa,CAAC,EAAE,MAAM,CAAC;IAEvB,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAOD,MAAM,WAAW,eAAgB,SAAQ,SAAS;IAEhD,OAAO,CAAC,EAAE,MAAM,CAAC;IAEjB,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAcD,MAAM,WAAW,YAAa,SAC5B,UAAU,EACV,gBAAgB,EAChB,UAAU,EACV,eAAe;CAAG"}
|
|
1
|
+
{"version":3,"file":"core.d.ts","sourceRoot":"","sources":["../../source/types/core.ts"],"names":[],"mappings":"AAiBA,MAAM,WAAW,YAAY,CAAC,CAAC,GAAG,WAAW;IAE3C,OAAO,EAAE,CAAC,CAAC;IAEX,MAAM,EAAE,MAAM,CAAC;IAEf,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC;CACnC;AAOD,MAAM,WAAW,KAAK;IAEpB,GAAG,EAAE,MAAM,CAAC;IAEZ,GAAG,CAAC,EAAE,MAAM,CAAC;IAEb,OAAO,CAAC,EAAE,MAAM,CAAC;IAEjB,EAAE,CAAC,EAAE,MAAM,CAAC;CACb;AAOD,MAAM,WAAW,QAAQ;IAEvB,EAAE,CAAC,EAAE,MAAM,CAAC;IAEZ,KAAK,EAAE,MAAM,CAAC;IAEd,GAAG,EAAE,MAAM,CAAC;CACb;AAQD,MAAM,WAAW,SAAS;IAExB,EAAE,EAAE,MAAM,GAAG,MAAM,CAAC;IAEpB,KAAK,EAAE,MAAM,CAAC;IAEd,GAAG,EAAE,MAAM,CAAC;IAEZ,IAAI,CAAC,EAAE,MAAM,CAAC;IAEd,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAOD,MAAM,WAAW,UAAW,SAAQ,SAAS;IAE3C,KAAK,EAAE,KAAK,EAAE,CAAC;CAChB;AAOD,MAAM,WAAW,gBAAiB,SAAQ,SAAS;IAEjD,UAAU,CAAC,EAAE,QAAQ,EAAE,CAAC;CACzB;AAOD,MAAM,WAAW,UAAW,SAAQ,SAAS;IAE3C,IAAI,EAAE,MAAM,CAAC;IAEb,aAAa,CAAC,EAAE,MAAM,CAAC;IAEvB,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAOD,MAAM,WAAW,eAAgB,SAAQ,SAAS;IAEhD,OAAO,CAAC,EAAE,MAAM,CAAC;IAEjB,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAcD,MAAM,WAAW,YAAa,SAC5B,UAAU,EACV,gBAAgB,EAChB,UAAU,EACV,eAAe;CAAG"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@universityofmaryland/web-feeds-library",
|
|
3
|
-
"version": "1.3.9
|
|
3
|
+
"version": "1.3.9",
|
|
4
4
|
"description": "UMD Feed Elements",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -49,11 +49,11 @@
|
|
|
49
49
|
},
|
|
50
50
|
"dependencies": {
|
|
51
51
|
"@types/postcss-js": "^4.0.4",
|
|
52
|
-
"@universityofmaryland/web-builder-library": "^1.0.3
|
|
53
|
-
"@universityofmaryland/web-elements-library": "^1.6.10
|
|
52
|
+
"@universityofmaryland/web-builder-library": "^1.0.3",
|
|
53
|
+
"@universityofmaryland/web-elements-library": "^1.6.10",
|
|
54
54
|
"@universityofmaryland/web-token-library": "^1.0.1",
|
|
55
|
-
"@universityofmaryland/web-
|
|
56
|
-
"@universityofmaryland/web-
|
|
55
|
+
"@universityofmaryland/web-utilities-library": "^1.0.5",
|
|
56
|
+
"@universityofmaryland/web-styles-library": "^1.8.6"
|
|
57
57
|
},
|
|
58
58
|
"peerDependencies": {
|
|
59
59
|
"@universityofmaryland/web-builder-library": "^1.0.0",
|