@universityofmaryland/web-feeds-library 1.3.0-beta.0 → 1.3.0-beta.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/academic.js +4 -4
- package/dist/academic.js.map +1 -1
- package/dist/events.js +10 -10
- package/dist/events.js.map +1 -1
- package/dist/experts.js +8 -8
- package/dist/experts.js.map +1 -1
- package/dist/factory/core/createBaseFeed.d.ts.map +1 -1
- package/dist/factory/core/createBaseFeed.js +19 -17
- package/dist/factory/core/createBaseFeed.js.map +1 -1
- package/dist/factory/core/types.d.ts +1 -0
- package/dist/factory/core/types.d.ts.map +1 -1
- package/dist/factory/helpers/displayHandler.js +29 -47
- package/dist/factory/helpers/displayHandler.js.map +1 -1
- package/dist/factory/helpers/feedHelpers.js +3 -3
- package/dist/factory/helpers/feedHelpers.js.map +1 -1
- package/dist/factory/helpers/fetchHandler.js +16 -33
- package/dist/factory/helpers/fetchHandler.js.map +1 -1
- package/dist/feeds/academic/index.d.ts +1 -1
- package/dist/feeds/academic/index.d.ts.map +1 -1
- package/dist/feeds/academic/slider.d.ts +1 -2
- package/dist/feeds/academic/slider.d.ts.map +1 -1
- package/dist/feeds/academic/slider.js +7 -6
- package/dist/feeds/academic/slider.js.map +1 -1
- package/dist/feeds/events/grid.d.ts +1 -2
- package/dist/feeds/events/grid.d.ts.map +1 -1
- package/dist/feeds/events/grid.js +22 -21
- package/dist/feeds/events/grid.js.map +1 -1
- package/dist/feeds/events/grouped.d.ts +1 -2
- package/dist/feeds/events/grouped.d.ts.map +1 -1
- package/dist/feeds/events/grouped.js +62 -78
- package/dist/feeds/events/grouped.js.map +1 -1
- package/dist/feeds/events/index.d.ts +4 -4
- package/dist/feeds/events/index.d.ts.map +1 -1
- package/dist/feeds/events/list.d.ts +1 -2
- package/dist/feeds/events/list.d.ts.map +1 -1
- package/dist/feeds/events/list.js +22 -21
- package/dist/feeds/events/list.js.map +1 -1
- package/dist/feeds/events/slider.d.ts +1 -2
- package/dist/feeds/events/slider.d.ts.map +1 -1
- package/dist/feeds/events/slider.js +7 -6
- package/dist/feeds/events/slider.js.map +1 -1
- package/dist/feeds/experts/_types.d.ts +2 -1
- package/dist/feeds/experts/_types.d.ts.map +1 -1
- package/dist/feeds/experts/bio.d.ts +1 -2
- package/dist/feeds/experts/bio.d.ts.map +1 -1
- package/dist/feeds/experts/bio.js +32 -31
- package/dist/feeds/experts/bio.js.map +1 -1
- package/dist/feeds/experts/grid.d.ts +1 -2
- package/dist/feeds/experts/grid.d.ts.map +1 -1
- package/dist/feeds/experts/grid.js +24 -23
- package/dist/feeds/experts/grid.js.map +1 -1
- package/dist/feeds/experts/index.d.ts +3 -3
- package/dist/feeds/experts/index.d.ts.map +1 -1
- package/dist/feeds/experts/list.d.ts +1 -2
- package/dist/feeds/experts/list.d.ts.map +1 -1
- package/dist/feeds/experts/list.js +23 -22
- package/dist/feeds/experts/list.js.map +1 -1
- package/dist/feeds/news/featured.d.ts +1 -2
- package/dist/feeds/news/featured.d.ts.map +1 -1
- package/dist/feeds/news/featured.js +56 -55
- package/dist/feeds/news/featured.js.map +1 -1
- package/dist/feeds/news/grid.d.ts +1 -2
- package/dist/feeds/news/grid.d.ts.map +1 -1
- package/dist/feeds/news/grid.js +24 -23
- package/dist/feeds/news/grid.js.map +1 -1
- package/dist/feeds/news/index.d.ts +3 -3
- package/dist/feeds/news/index.d.ts.map +1 -1
- package/dist/feeds/news/list.d.ts +1 -2
- package/dist/feeds/news/list.d.ts.map +1 -1
- package/dist/feeds/news/list.js +23 -22
- package/dist/feeds/news/list.js.map +1 -1
- package/dist/helpers/events/index.js +4 -4
- package/dist/helpers/events/index.js.map +1 -1
- package/dist/helpers/grouping/events.js +10 -10
- package/dist/helpers/grouping/events.js.map +1 -1
- package/dist/helpers/styles/shadow.js +5 -22
- package/dist/helpers/styles/shadow.js.map +1 -1
- package/dist/index.js +10 -10
- package/dist/index.js.map +1 -1
- package/dist/news.js +8 -8
- package/dist/news.js.map +1 -1
- package/dist/states/_types.d.ts +0 -24
- package/dist/states/_types.d.ts.map +1 -1
- package/dist/states/_types.js +3 -3
- package/dist/states/_types.js.map +1 -1
- package/dist/states/announcer.d.ts +1 -3
- package/dist/states/announcer.d.ts.map +1 -1
- package/dist/states/announcer.js +5 -5
- package/dist/states/announcer.js.map +1 -1
- package/dist/states/empty.d.ts +0 -2
- package/dist/states/empty.d.ts.map +1 -1
- package/dist/states/empty.js +15 -32
- package/dist/states/empty.js.map +1 -1
- package/dist/states/index.d.ts +4 -8
- package/dist/states/index.d.ts.map +1 -1
- package/dist/states/loading.d.ts +1 -3
- package/dist/states/loading.d.ts.map +1 -1
- package/dist/states/loading.js +16 -16
- package/dist/states/loading.js.map +1 -1
- package/dist/states/pagination.d.ts +1 -3
- package/dist/states/pagination.d.ts.map +1 -1
- package/dist/states/pagination.js +11 -28
- package/dist/states/pagination.js.map +1 -1
- package/dist/strategies/display/events.js +13 -13
- package/dist/strategies/display/events.js.map +1 -1
- package/dist/strategies/display/experts.js +23 -23
- package/dist/strategies/display/experts.js.map +1 -1
- package/dist/strategies/display/news.js +13 -13
- package/dist/strategies/display/news.js.map +1 -1
- package/dist/strategies/fetch/academic.js +3 -3
- package/dist/strategies/fetch/academic.js.map +1 -1
- package/dist/strategies/fetch/events.js +13 -13
- package/dist/strategies/fetch/events.js.map +1 -1
- package/dist/strategies/fetch/experts.d.ts +1 -1
- package/dist/strategies/fetch/experts.d.ts.map +1 -1
- package/dist/strategies/fetch/experts.js +13 -8
- package/dist/strategies/fetch/experts.js.map +1 -1
- package/dist/strategies/fetch/graphql.d.ts.map +1 -1
- package/dist/strategies/fetch/graphql.js +11 -7
- package/dist/strategies/fetch/graphql.js.map +1 -1
- package/dist/strategies/fetch/news.js +6 -6
- package/dist/strategies/fetch/news.js.map +1 -1
- package/dist/strategies/layout/grid.js +11 -11
- package/dist/strategies/layout/grid.js.map +1 -1
- package/dist/widgets/index.d.ts +1 -1
- package/dist/widgets/index.d.ts.map +1 -1
- package/dist/widgets/slider.d.ts +1 -2
- package/dist/widgets/slider.d.ts.map +1 -1
- package/dist/widgets/slider.js +19 -35
- package/dist/widgets/slider.js.map +1 -1
- package/package.json +15 -14
- package/dist/academic.mjs +0 -5
- package/dist/academic.mjs.map +0 -1
- package/dist/events.mjs +0 -11
- package/dist/events.mjs.map +0 -1
- package/dist/experts.mjs +0 -9
- package/dist/experts.mjs.map +0 -1
- package/dist/factory/core/createBaseFeed.mjs +0 -114
- package/dist/factory/core/createBaseFeed.mjs.map +0 -1
- package/dist/factory/helpers/displayHandler.mjs +0 -169
- package/dist/factory/helpers/displayHandler.mjs.map +0 -1
- package/dist/factory/helpers/feedHelpers.mjs +0 -32
- package/dist/factory/helpers/feedHelpers.mjs.map +0 -1
- package/dist/factory/helpers/fetchHandler.mjs +0 -123
- package/dist/factory/helpers/fetchHandler.mjs.map +0 -1
- package/dist/feeds/academic/slider.mjs +0 -11
- package/dist/feeds/academic/slider.mjs.map +0 -1
- package/dist/feeds/events/grid.mjs +0 -32
- package/dist/feeds/events/grid.mjs.map +0 -1
- package/dist/feeds/events/grouped.mjs +0 -337
- package/dist/feeds/events/grouped.mjs.map +0 -1
- package/dist/feeds/events/list.mjs +0 -33
- package/dist/feeds/events/list.mjs.map +0 -1
- package/dist/feeds/events/slider.mjs +0 -11
- package/dist/feeds/events/slider.mjs.map +0 -1
- package/dist/feeds/experts/bio.mjs +0 -147
- package/dist/feeds/experts/bio.mjs.map +0 -1
- package/dist/feeds/experts/grid.mjs +0 -37
- package/dist/feeds/experts/grid.mjs.map +0 -1
- package/dist/feeds/experts/list.mjs +0 -26
- package/dist/feeds/experts/list.mjs.map +0 -1
- package/dist/feeds/news/featured.mjs +0 -379
- package/dist/feeds/news/featured.mjs.map +0 -1
- package/dist/feeds/news/grid.mjs +0 -37
- package/dist/feeds/news/grid.mjs.map +0 -1
- package/dist/feeds/news/list.mjs +0 -34
- package/dist/feeds/news/list.mjs.map +0 -1
- package/dist/helpers/events/index.mjs +0 -21
- package/dist/helpers/events/index.mjs.map +0 -1
- package/dist/helpers/grouping/events.mjs +0 -147
- package/dist/helpers/grouping/events.mjs.map +0 -1
- package/dist/helpers/styles/shadow.mjs +0 -16
- package/dist/helpers/styles/shadow.mjs.map +0 -1
- package/dist/index.mjs +0 -11
- package/dist/index.mjs.map +0 -1
- package/dist/news.mjs +0 -9
- package/dist/news.mjs.map +0 -1
- package/dist/states/_types.mjs +0 -12
- package/dist/states/_types.mjs.map +0 -1
- package/dist/states/announcer.mjs +0 -62
- package/dist/states/announcer.mjs.map +0 -1
- package/dist/states/empty.mjs +0 -104
- package/dist/states/empty.mjs.map +0 -1
- package/dist/states/loading.mjs +0 -155
- package/dist/states/loading.mjs.map +0 -1
- package/dist/states/pagination.mjs +0 -102
- package/dist/states/pagination.mjs.map +0 -1
- package/dist/strategies/display/events.mjs +0 -60
- package/dist/strategies/display/events.mjs.map +0 -1
- package/dist/strategies/display/experts.mjs +0 -266
- package/dist/strategies/display/experts.mjs.map +0 -1
- package/dist/strategies/display/news.mjs +0 -58
- package/dist/strategies/display/news.mjs.map +0 -1
- package/dist/strategies/fetch/academic.mjs +0 -30
- package/dist/strategies/fetch/academic.mjs.map +0 -1
- package/dist/strategies/fetch/events.mjs +0 -223
- package/dist/strategies/fetch/events.mjs.map +0 -1
- package/dist/strategies/fetch/experts.mjs +0 -189
- package/dist/strategies/fetch/experts.mjs.map +0 -1
- package/dist/strategies/fetch/graphql.mjs +0 -100
- package/dist/strategies/fetch/graphql.mjs.map +0 -1
- package/dist/strategies/fetch/news.mjs +0 -95
- package/dist/strategies/fetch/news.mjs.map +0 -1
- package/dist/strategies/layout/grid.mjs +0 -36
- package/dist/strategies/layout/grid.mjs.map +0 -1
- package/dist/widgets/slider.mjs +0 -87
- package/dist/widgets/slider.mjs.map +0 -1
|
@@ -1,15 +1,14 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
const shadow = require("../../helpers/styles/shadow.js");
|
|
1
|
+
import { ElementBuilder } from "@universityofmaryland/web-builder-library";
|
|
2
|
+
import { card } from "@universityofmaryland/web-elements-library/composite";
|
|
3
|
+
import { gridOffset, gridGap } from "@universityofmaryland/web-elements-library/layout";
|
|
4
|
+
import { LoadingState } from "../../states/loading.js";
|
|
5
|
+
import { EmptyState } from "../../states/empty.js";
|
|
6
|
+
import { PaginationState } from "../../states/pagination.js";
|
|
7
|
+
import { Announcer } from "../../states/announcer.js";
|
|
8
|
+
import { newsFetchStrategy } from "../../strategies/fetch/news.js";
|
|
9
|
+
import { newsDisplayStrategy } from "../../strategies/display/news.js";
|
|
10
|
+
import { dispatch, eventNames } from "../../helpers/events/index.js";
|
|
11
|
+
import { setShadowStyles } from "../../helpers/styles/shadow.js";
|
|
13
12
|
const INITIAL_ITEMS = 3;
|
|
14
13
|
const LOAD_MORE_ITEMS = 2;
|
|
15
14
|
const createFetchProps = (props, offset) => ({
|
|
@@ -57,8 +56,8 @@ class FeaturedFeedState {
|
|
|
57
56
|
*
|
|
58
57
|
* @param shadow - Shadow root element
|
|
59
58
|
*/
|
|
60
|
-
setShadowRoot(
|
|
61
|
-
this.shadowRoot =
|
|
59
|
+
setShadowRoot(shadow) {
|
|
60
|
+
this.shadowRoot = shadow;
|
|
62
61
|
}
|
|
63
62
|
/**
|
|
64
63
|
* Update shadow DOM styles
|
|
@@ -67,7 +66,7 @@ class FeaturedFeedState {
|
|
|
67
66
|
*/
|
|
68
67
|
async updateShadowStyles() {
|
|
69
68
|
if (!this.shadowRoot) return;
|
|
70
|
-
await
|
|
69
|
+
await setShadowStyles({
|
|
71
70
|
shadowRoot: this.shadowRoot,
|
|
72
71
|
styles: this.getStyles()
|
|
73
72
|
});
|
|
@@ -86,7 +85,7 @@ class FeaturedFeedState {
|
|
|
86
85
|
* @returns Callback function for shadow root
|
|
87
86
|
*/
|
|
88
87
|
getShadowCallback() {
|
|
89
|
-
return (
|
|
88
|
+
return (shadow) => this.setShadowRoot(shadow);
|
|
90
89
|
}
|
|
91
90
|
/**
|
|
92
91
|
* Get current offset
|
|
@@ -155,12 +154,12 @@ class FeaturedFeedState {
|
|
|
155
154
|
*
|
|
156
155
|
* @param pagination - Pagination state
|
|
157
156
|
*/
|
|
158
|
-
setPagination(
|
|
159
|
-
this.pagination =
|
|
157
|
+
setPagination(pagination) {
|
|
158
|
+
this.pagination = pagination;
|
|
160
159
|
}
|
|
161
160
|
}
|
|
162
161
|
const createOverlayCard = (entry, state, isThemeDark) => {
|
|
163
|
-
const overlayCard =
|
|
162
|
+
const overlayCard = newsDisplayStrategy.mapEntryToCard(entry, {
|
|
164
163
|
isOverlay: true,
|
|
165
164
|
isThemeDark,
|
|
166
165
|
imageConfig: () => createImageConfig(entry)
|
|
@@ -168,11 +167,11 @@ const createOverlayCard = (entry, state, isThemeDark) => {
|
|
|
168
167
|
state.addStyles(`
|
|
169
168
|
${overlayCard.styles}
|
|
170
169
|
|
|
171
|
-
.${
|
|
170
|
+
.${card.overlay.imageClassRef} {
|
|
172
171
|
height: inherit;
|
|
173
172
|
}
|
|
174
173
|
|
|
175
|
-
.${
|
|
174
|
+
.${card.overlay.imageClassRef} .umd-asset-image-wrapper-scaled {
|
|
176
175
|
position: absolute;
|
|
177
176
|
}
|
|
178
177
|
`);
|
|
@@ -180,7 +179,7 @@ const createOverlayCard = (entry, state, isThemeDark) => {
|
|
|
180
179
|
};
|
|
181
180
|
const createBlockCards = (entries, state, options) => {
|
|
182
181
|
return entries.map((entry) => {
|
|
183
|
-
const blockCard =
|
|
182
|
+
const blockCard = newsDisplayStrategy.mapEntryToCard(entry, {
|
|
184
183
|
isThemeDark: options.isThemeDark,
|
|
185
184
|
isTransparent: options.isTransparent,
|
|
186
185
|
isAligned: true,
|
|
@@ -205,12 +204,12 @@ const renderFeaturedLayout = async (container, entries, state, props, loadMore)
|
|
|
205
204
|
});
|
|
206
205
|
}
|
|
207
206
|
state.markOffsetRendered();
|
|
208
|
-
const offsetLayout =
|
|
207
|
+
const offsetLayout = gridOffset({
|
|
209
208
|
columns: 2,
|
|
210
209
|
isLayoutReversed,
|
|
211
210
|
stickyTopPosition: overwriteStickyPosition
|
|
212
211
|
});
|
|
213
|
-
const gridLayout =
|
|
212
|
+
const gridLayout = gridGap({ columns: 2 });
|
|
214
213
|
gridLayout.element.setAttribute("id", "umd-featured-news-grid-container");
|
|
215
214
|
const overlayCard = createOverlayCard(entries[0], state, isThemeDark);
|
|
216
215
|
const blockCards = createBlockCards(entries.slice(1, 3), state, {
|
|
@@ -227,23 +226,23 @@ const renderFeaturedLayout = async (container, entries, state, props, loadMore)
|
|
|
227
226
|
state.addStyles(gridLayout.styles);
|
|
228
227
|
state.setOffset(3);
|
|
229
228
|
if (isLazyLoad && state.getTotalEntries() > state.getOffset()) {
|
|
230
|
-
const pagination
|
|
229
|
+
const pagination = new PaginationState({
|
|
231
230
|
totalEntries: state.getTotalEntries(),
|
|
232
231
|
offset: state.getOffset(),
|
|
233
232
|
isLazyLoad: true,
|
|
234
233
|
callback: loadMore
|
|
235
234
|
});
|
|
236
|
-
const paginationElement = pagination
|
|
235
|
+
const paginationElement = pagination.render(container);
|
|
237
236
|
if (paginationElement) state.addStyles(paginationElement.styles);
|
|
238
|
-
state.setPagination(pagination
|
|
237
|
+
state.setPagination(pagination);
|
|
239
238
|
}
|
|
240
239
|
const message = createAnnouncerMessage(
|
|
241
240
|
INITIAL_ITEMS,
|
|
242
241
|
state.getTotalEntries(),
|
|
243
242
|
isLazyLoad
|
|
244
243
|
);
|
|
245
|
-
const announcer
|
|
246
|
-
container.appendChild(announcer
|
|
244
|
+
const announcer = new Announcer({ message });
|
|
245
|
+
container.appendChild(announcer.getElement());
|
|
247
246
|
await state.updateShadowStyles();
|
|
248
247
|
};
|
|
249
248
|
const renderStandardGrid = async (container, entries, state, options) => {
|
|
@@ -251,7 +250,7 @@ const renderStandardGrid = async (container, entries, state, options) => {
|
|
|
251
250
|
"#umd-featured-news-grid-container"
|
|
252
251
|
);
|
|
253
252
|
if (!gridContainer) {
|
|
254
|
-
const gridLayout =
|
|
253
|
+
const gridLayout = gridGap({ columns: 2 });
|
|
255
254
|
gridLayout.element.setAttribute("id", "umd-featured-news-grid-container");
|
|
256
255
|
container.appendChild(gridLayout.element);
|
|
257
256
|
state.addStyles(gridLayout.styles);
|
|
@@ -265,12 +264,12 @@ const renderStandardGrid = async (container, entries, state, options) => {
|
|
|
265
264
|
await state.updateShadowStyles();
|
|
266
265
|
};
|
|
267
266
|
const renderError = async (container, message, state, isThemeDark) => {
|
|
268
|
-
const emptyState = new
|
|
267
|
+
const emptyState = new EmptyState({ message, isThemeDark });
|
|
269
268
|
emptyState.render(container);
|
|
270
269
|
state.addStyles(emptyState.styles);
|
|
271
270
|
await state.updateShadowStyles();
|
|
272
271
|
};
|
|
273
|
-
const
|
|
272
|
+
const newsFeatured = (props) => {
|
|
274
273
|
const {
|
|
275
274
|
token,
|
|
276
275
|
categories,
|
|
@@ -279,33 +278,33 @@ const featured = (props) => {
|
|
|
279
278
|
isLazyLoad = false,
|
|
280
279
|
isTransparent = false
|
|
281
280
|
} = props;
|
|
282
|
-
const containerBuilder = new
|
|
281
|
+
const containerBuilder = new ElementBuilder("div").withClassName(
|
|
283
282
|
"featured-news-feed"
|
|
284
283
|
);
|
|
285
284
|
const container = containerBuilder.getElement();
|
|
286
|
-
const loading
|
|
287
|
-
const state = new FeaturedFeedState(loading
|
|
285
|
+
const loading = new LoadingState({ isThemeDark });
|
|
286
|
+
const state = new FeaturedFeedState(loading.styles);
|
|
288
287
|
const loadMore = async () => {
|
|
289
|
-
const
|
|
290
|
-
if (
|
|
291
|
-
|
|
288
|
+
const pagination = state.getPagination();
|
|
289
|
+
if (pagination) {
|
|
290
|
+
pagination.remove();
|
|
292
291
|
}
|
|
293
|
-
loading
|
|
292
|
+
loading.show(container);
|
|
294
293
|
const fetchProps = createFetchProps(
|
|
295
294
|
{ token, categories, isUnion },
|
|
296
295
|
state.getOffset()
|
|
297
296
|
);
|
|
298
|
-
const variables =
|
|
299
|
-
const entries = await
|
|
300
|
-
loading
|
|
297
|
+
const variables = newsFetchStrategy.composeApiVariables(fetchProps);
|
|
298
|
+
const entries = await newsFetchStrategy.fetchEntries(variables);
|
|
299
|
+
loading.hide();
|
|
301
300
|
if (!entries || entries.length === 0) return;
|
|
302
301
|
await renderStandardGrid(container, entries, state, {
|
|
303
302
|
isThemeDark,
|
|
304
303
|
isTransparent
|
|
305
304
|
});
|
|
306
|
-
if (
|
|
307
|
-
|
|
308
|
-
if (
|
|
305
|
+
if (pagination) {
|
|
306
|
+
pagination.updateState(state.getOffset(), state.getTotalEntries());
|
|
307
|
+
if (pagination.styles) state.addStyles(pagination.styles);
|
|
309
308
|
await state.updateShadowStyles();
|
|
310
309
|
}
|
|
311
310
|
const existingAnnouncer = container.querySelector(
|
|
@@ -318,9 +317,9 @@ const featured = (props) => {
|
|
|
318
317
|
isLazyLoad
|
|
319
318
|
);
|
|
320
319
|
}
|
|
321
|
-
|
|
320
|
+
dispatch(
|
|
322
321
|
container,
|
|
323
|
-
|
|
322
|
+
eventNames.FEED_LOADED_MORE,
|
|
324
323
|
{
|
|
325
324
|
items: entries,
|
|
326
325
|
count: entries.length,
|
|
@@ -329,14 +328,14 @@ const featured = (props) => {
|
|
|
329
328
|
);
|
|
330
329
|
};
|
|
331
330
|
const initialize = async () => {
|
|
332
|
-
loading
|
|
331
|
+
loading.show(container);
|
|
333
332
|
const fetchProps = createFetchProps({ token, categories, isUnion }, 0);
|
|
334
|
-
const variables =
|
|
333
|
+
const variables = newsFetchStrategy.composeApiVariables(fetchProps);
|
|
335
334
|
const [count, entries] = await Promise.all([
|
|
336
|
-
|
|
337
|
-
|
|
335
|
+
newsFetchStrategy.fetchCount(variables),
|
|
336
|
+
newsFetchStrategy.fetchEntries(variables)
|
|
338
337
|
]);
|
|
339
|
-
loading
|
|
338
|
+
loading.hide();
|
|
340
339
|
if (!entries || entries.length === 0) {
|
|
341
340
|
await renderError(
|
|
342
341
|
container,
|
|
@@ -347,7 +346,7 @@ const featured = (props) => {
|
|
|
347
346
|
return;
|
|
348
347
|
}
|
|
349
348
|
state.setTotalEntries(count || entries.length);
|
|
350
|
-
|
|
349
|
+
dispatch(container, eventNames.FEED_LOADED, {
|
|
351
350
|
items: entries,
|
|
352
351
|
count: entries.length,
|
|
353
352
|
total: state.getTotalEntries()
|
|
@@ -358,7 +357,7 @@ const featured = (props) => {
|
|
|
358
357
|
const model = containerBuilder.build();
|
|
359
358
|
const setPosition = (position) => {
|
|
360
359
|
const overlayElement = container.querySelector(
|
|
361
|
-
`.${
|
|
360
|
+
`.${card.overlay.imageClassRef}`
|
|
362
361
|
);
|
|
363
362
|
if (overlayElement) overlayElement.style.top = `${position}px`;
|
|
364
363
|
};
|
|
@@ -374,5 +373,7 @@ const featured = (props) => {
|
|
|
374
373
|
}
|
|
375
374
|
};
|
|
376
375
|
};
|
|
377
|
-
|
|
376
|
+
export {
|
|
377
|
+
newsFeatured
|
|
378
|
+
};
|
|
378
379
|
//# sourceMappingURL=featured.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"featured.js","sources":["../../../source/feeds/news/featured.ts"],"sourcesContent":["/**\n * News Featured Feed (Refactored with Element Builder)\n *\n * Displays news articles with a featured layout:\n * - First article: Large overlay card with sticky positioning\n * - Next 2 articles: Block cards in grid layout\n * - Additional articles: Lazy-loaded block cards\n *\n * Uses Element Builder pattern for clean, declarative construction.\n *\n * @module feeds/news/featured\n */\n\nimport { ElementBuilder } from '@universityofmaryland/web-builder-library';\nimport { card } from '@universityofmaryland/web-elements-library/composite';\nimport {\n gridGap,\n gridOffset,\n} from '@universityofmaryland/web-elements-library/layout';\nimport {\n LoadingState,\n PaginationState,\n EmptyState,\n Announcer,\n} from '../../states';\nimport { newsFetchStrategy } from '../../strategies/fetch/news';\nimport { newsDisplayStrategy } from '../../strategies/display/news';\nimport {\n events as eventUtilities,\n styles as styleUtilities,\n} from '../../helpers';\nimport { type FeaturedProps } from './_types';\nimport { type ElementModel } from '../../_types';\nimport { type NewsEntry } from 'types/data';\n\n// ============================================================================\n// CONSTANTS\n// ============================================================================\n\n/** Featured layout displays 3 items initially: 1 overlay + 2 block cards */\nconst INITIAL_ITEMS = 3;\n\n/** Lazy loading adds 2 items at a time to fill a row in the 2-column grid */\nconst LOAD_MORE_ITEMS = 2;\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<FeaturedProps, 'token' | 'categories' | 'isUnion'>,\n offset: number,\n) => ({\n token: props.token,\n categories: props.categories,\n isUnion: props.isUnion,\n numberOfRowsToStart: offset === 0 ? INITIAL_ITEMS : LOAD_MORE_ITEMS,\n numberOfColumnsToShow: 1,\n getOffset: () => offset,\n});\n\n/**\n * Create image configuration for news entry\n *\n * @param entry - News entry\n * @returns Image config object\n */\nconst createImageConfig = (entry: NewsEntry) => ({\n imageUrl: entry.image[0]?.url,\n altText: entry.image[0]?.altText || 'News Article Image',\n linkUrl: entry.url,\n linkLabel: 'Maryland Today Article with image',\n});\n\n/**\n * Create announcer message\n *\n * @param offset - Current offset\n * @param total - Total entries\n * @param isLazyLoad - Lazy load enabled\n * @returns Announcer message\n */\nconst createAnnouncerMessage = (\n offset: number,\n total: number,\n isLazyLoad: boolean,\n): string => {\n return isLazyLoad\n ? `Showing ${offset} of ${total} articles`\n : `Showing ${offset} articles`;\n};\n\n// ============================================================================\n// STATE MANAGER CLASS\n// ============================================================================\n\n/**\n * Manages featured feed state and shadow DOM synchronization\n *\n * Encapsulates all mutable state including pagination, offset,\n * and shadow DOM management.\n */\nclass FeaturedFeedState {\n private stylesArray: string[] = [];\n private shadowRoot: ShadowRoot | null = null;\n private totalEntries: number = 0;\n private offset: number = 0;\n private hasRenderedOffset: boolean = false;\n private pagination: PaginationState | 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 * Set offset to specific value\n *\n * @param value - New offset value\n */\n setOffset(value: number): void {\n this.offset = value;\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 * Check if offset layout has been rendered\n *\n * @returns True if offset layout rendered\n */\n hasOffset(): boolean {\n return this.hasRenderedOffset;\n }\n\n /**\n * Mark offset layout as rendered\n */\n markOffsetRendered(): void {\n this.hasRenderedOffset = true;\n }\n\n /**\n * Get pagination state\n *\n * @returns Pagination state or null\n */\n getPagination(): PaginationState | null {\n return this.pagination;\n }\n\n /**\n * Set pagination state\n *\n * @param pagination - Pagination state\n */\n setPagination(pagination: PaginationState | null): void {\n this.pagination = pagination;\n }\n}\n\n// ============================================================================\n// RENDERING FUNCTIONS\n// ============================================================================\n\n/**\n * Create overlay card for featured entry\n *\n * @param entry - News entry\n * @param state - State manager\n * @param isThemeDark - Dark theme flag\n * @returns Overlay card element model\n */\nconst createOverlayCard = (\n entry: NewsEntry,\n state: FeaturedFeedState,\n isThemeDark: boolean,\n): ElementModel => {\n const overlayCard = newsDisplayStrategy.mapEntryToCard(entry, {\n isOverlay: true,\n isThemeDark,\n imageConfig: () => createImageConfig(entry),\n });\n\n // Add custom overlay styles\n state.addStyles(`\n ${overlayCard.styles}\n\n .${card.overlay.imageClassRef} {\n height: inherit;\n }\n\n .${card.overlay.imageClassRef} .umd-asset-image-wrapper-scaled {\n position: absolute;\n }\n `);\n\n return overlayCard;\n};\n\n/**\n * Create block cards for entries\n *\n * @param entries - News entries\n * @param state - State manager\n * @param options - Card options\n * @returns Array of block card element models\n */\nconst createBlockCards = (\n entries: NewsEntry[],\n state: FeaturedFeedState,\n options: { isThemeDark: boolean; isTransparent: boolean },\n): ElementModel[] => {\n return entries.map((entry) => {\n const blockCard = newsDisplayStrategy.mapEntryToCard(entry, {\n isThemeDark: options.isThemeDark,\n isTransparent: options.isTransparent,\n isAligned: true,\n imageConfig: () => createImageConfig(entry),\n });\n\n state.addStyles(blockCard.styles);\n return blockCard;\n });\n};\n\n/**\n * Render featured layout (initial load only)\n *\n * @param container - Container element\n * @param entries - News entries\n * @param state - State manager\n * @param props - Feed props\n * @param loadMore - Load more callback\n * @returns Promise that resolves when rendering is complete\n */\nconst renderFeaturedLayout = async (\n container: HTMLElement,\n entries: NewsEntry[],\n state: FeaturedFeedState,\n props: FeaturedProps,\n loadMore: () => Promise<void>,\n): Promise<void> => {\n const {\n isThemeDark = false,\n isTransparent = false,\n isLayoutReversed = false,\n overwriteStickyPosition,\n isLazyLoad = false,\n } = props;\n\n // Fall back to standard grid if not enough entries or already rendered\n if (entries.length < 2 || state.hasOffset()) {\n return renderStandardGrid(container, entries, state, {\n isThemeDark,\n isTransparent,\n });\n }\n\n state.markOffsetRendered();\n\n // Create offset layout\n const offsetLayout = gridOffset({\n columns: 2,\n isLayoutReversed,\n stickyTopPosition: overwriteStickyPosition,\n });\n\n // Create grid for remaining items\n const gridLayout = gridGap({ columns: 2 });\n gridLayout.element.setAttribute('id', 'umd-featured-news-grid-container');\n\n // First item: overlay card\n const overlayCard = createOverlayCard(entries[0], state, isThemeDark);\n\n // Next 2 items: block cards\n const blockCards = createBlockCards(entries.slice(1, 3), state, {\n isThemeDark,\n isTransparent,\n });\n\n // Append block cards to grid\n blockCards.forEach((card) => {\n gridLayout.element.appendChild(card.element);\n });\n\n // Assemble offset layout\n offsetLayout.element.appendChild(overlayCard.element);\n offsetLayout.element.appendChild(gridLayout.element);\n container.appendChild(offsetLayout.element);\n\n state.addStyles(offsetLayout.styles);\n state.addStyles(gridLayout.styles);\n state.setOffset(3); // We've shown 3 items\n\n // Add pagination if needed\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) state.addStyles(paginationElement.styles);\n state.setPagination(pagination);\n }\n\n // Announcer\n const message = createAnnouncerMessage(\n INITIAL_ITEMS,\n state.getTotalEntries(),\n isLazyLoad,\n );\n const announcer = new Announcer({ message });\n container.appendChild(announcer.getElement());\n\n await state.updateShadowStyles();\n};\n\n/**\n * Render standard grid (for lazy-loaded items or fallback)\n *\n * @param container - Container element\n * @param entries - News entries\n * @param state - State manager\n * @param options - Rendering options\n * @returns Promise that resolves when rendering is complete\n */\nconst renderStandardGrid = async (\n container: HTMLElement,\n entries: NewsEntry[],\n state: FeaturedFeedState,\n options: { isThemeDark: boolean; isTransparent: boolean },\n): Promise<void> => {\n let gridContainer = container.querySelector(\n '#umd-featured-news-grid-container',\n ) as HTMLElement;\n\n // Create grid if it doesn't exist\n if (!gridContainer) {\n const gridLayout = gridGap({ columns: 2 });\n gridLayout.element.setAttribute('id', 'umd-featured-news-grid-container');\n container.appendChild(gridLayout.element);\n state.addStyles(gridLayout.styles);\n gridContainer = gridLayout.element;\n }\n\n // Create and append block cards\n const blockCards = createBlockCards(entries, state, options);\n blockCards.forEach((card) => {\n gridContainer.appendChild(card.element);\n });\n\n state.incrementOffset(entries.length);\n\n await state.updateShadowStyles();\n};\n\n/**\n * Render error state\n *\n * @param container - Container element\n * @param message - Error message\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 message: string,\n state: FeaturedFeedState,\n isThemeDark: boolean,\n): Promise<void> => {\n const emptyState = new EmptyState({ message, isThemeDark });\n emptyState.render(container);\n state.addStyles(emptyState.styles);\n await state.updateShadowStyles();\n};\n\n// ============================================================================\n// MAIN EXPORT\n// ============================================================================\n\n/**\n * Create a featured news feed\n *\n * Displays news with featured layout: overlay card + grid.\n * Uses Element Builder pattern for clean construction.\n *\n * @param props - Feed configuration\n * @returns ElementModel with feed element, styles, and events\n *\n * @example\n * ```typescript\n * const feed = newsFeatured({\n * token: 'my-token',\n * isLazyLoad: true,\n * });\n * ```\n *\n * @example\n * ```typescript\n * // With custom sticky position\n * const feed = newsFeatured({\n * token: 'my-token',\n * overwriteStickyPosition: 100,\n * isLayoutReversed: true,\n * });\n * ```\n */\nexport default (props: FeaturedProps): ElementModel => {\n const {\n token,\n categories,\n isUnion,\n isThemeDark = false,\n isLazyLoad = false,\n isTransparent = false,\n } = props;\n\n // Create container using ElementBuilder\n const containerBuilder = new ElementBuilder('div').withClassName(\n 'featured-news-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 FeaturedFeedState(loading.styles);\n\n /**\n * Load more articles (for lazy loading)\n */\n const loadMore = async (): Promise<void> => {\n // Remove pagination button\n const pagination = state.getPagination();\n if (pagination) {\n pagination.remove();\n }\n\n // Show loading indicator\n loading.show(container);\n\n // Load more items\n const fetchProps = createFetchProps(\n { token, categories, isUnion },\n state.getOffset(),\n );\n const variables = newsFetchStrategy.composeApiVariables(fetchProps);\n\n const entries = await newsFetchStrategy.fetchEntries(variables);\n\n // Hide loading indicator\n loading.hide();\n\n if (!entries || entries.length === 0) return;\n\n await renderStandardGrid(container, entries, state, {\n isThemeDark,\n isTransparent,\n });\n\n // Update pagination state\n if (pagination) {\n pagination.updateState(state.getOffset(), state.getTotalEntries());\n if (pagination.styles) state.addStyles(pagination.styles);\n await state.updateShadowStyles();\n }\n\n // Update announcer\n const existingAnnouncer = container.querySelector(\n '[role=\"status\"]',\n ) as HTMLElement;\n if (existingAnnouncer) {\n existingAnnouncer.textContent = createAnnouncerMessage(\n state.getOffset(),\n state.getTotalEntries(),\n isLazyLoad,\n );\n }\n\n // Dispatch update event\n eventUtilities.dispatch(\n container,\n eventUtilities.eventNames.FEED_LOADED_MORE,\n {\n items: entries,\n count: entries.length,\n total: state.getTotalEntries(),\n },\n );\n };\n\n /**\n * Initialize feed\n */\n const initialize = async (): Promise<void> => {\n loading.show(container);\n\n // Fetch initial items\n const fetchProps = createFetchProps({ token, categories, isUnion }, 0);\n const variables = newsFetchStrategy.composeApiVariables(fetchProps);\n\n const [count, entries] = await Promise.all([\n newsFetchStrategy.fetchCount(variables),\n newsFetchStrategy.fetchEntries(variables),\n ]);\n\n loading.hide();\n\n // Handle no results\n if (!entries || entries.length === 0) {\n await renderError(\n container,\n 'No news articles found',\n state,\n isThemeDark,\n );\n return;\n }\n\n state.setTotalEntries(count || entries.length);\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 featured layout\n await renderFeaturedLayout(container, entries, state, props, loadMore);\n };\n\n // Start initialization\n initialize();\n\n // Build and return element model\n const model = containerBuilder.build();\n\n // Custom event: allow external control of sticky position\n const setPosition = (position: number) => {\n const overlayElement = container.querySelector(\n `.${card.overlay.imageClassRef}`,\n ) as HTMLElement;\n if (overlayElement) overlayElement.style.top = `${position}px`;\n };\n\n return {\n element: model.element,\n get styles() {\n return state.getStyles();\n },\n events: {\n callback: state.getShadowCallback(),\n setPosition, // Custom event for sticky position control\n },\n };\n};\n"],"names":["shadow","styleUtilities.setShadowStyles","pagination","newsDisplayStrategy","card","gridOffset","gridGap","PaginationState","announcer","Announcer","EmptyState","ElementBuilder","loading","LoadingState","newsFetchStrategy","eventUtilities.dispatch","eventUtilities.eventNames"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"featured.js","sources":["../../../source/feeds/news/featured.ts"],"sourcesContent":["/**\n * News Featured Feed (Refactored with Element Builder)\n *\n * Displays news articles with a featured layout:\n * - First article: Large overlay card with sticky positioning\n * - Next 2 articles: Block cards in grid layout\n * - Additional articles: Lazy-loaded block cards\n *\n * Uses Element Builder pattern for clean, declarative construction.\n *\n * @module feeds/news/featured\n */\n\nimport { ElementBuilder } from '@universityofmaryland/web-builder-library';\nimport { card } from '@universityofmaryland/web-elements-library/composite';\nimport {\n gridGap,\n gridOffset,\n} from '@universityofmaryland/web-elements-library/layout';\nimport {\n LoadingState,\n PaginationState,\n EmptyState,\n Announcer,\n} from '../../states';\nimport { newsFetchStrategy } from '../../strategies/fetch/news';\nimport { newsDisplayStrategy } from '../../strategies/display/news';\nimport {\n events as eventUtilities,\n styles as styleUtilities,\n} from '../../helpers';\nimport { type FeaturedProps } from './_types';\nimport { type ElementModel } from '../../_types';\nimport { type NewsEntry } from 'types/data';\n\n// ============================================================================\n// CONSTANTS\n// ============================================================================\n\n/** Featured layout displays 3 items initially: 1 overlay + 2 block cards */\nconst INITIAL_ITEMS = 3;\n\n/** Lazy loading adds 2 items at a time to fill a row in the 2-column grid */\nconst LOAD_MORE_ITEMS = 2;\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<FeaturedProps, 'token' | 'categories' | 'isUnion'>,\n offset: number,\n) => ({\n token: props.token,\n categories: props.categories,\n isUnion: props.isUnion,\n numberOfRowsToStart: offset === 0 ? INITIAL_ITEMS : LOAD_MORE_ITEMS,\n numberOfColumnsToShow: 1,\n getOffset: () => offset,\n});\n\n/**\n * Create image configuration for news entry\n *\n * @param entry - News entry\n * @returns Image config object\n */\nconst createImageConfig = (entry: NewsEntry) => ({\n imageUrl: entry.image[0]?.url,\n altText: entry.image[0]?.altText || 'News Article Image',\n linkUrl: entry.url,\n linkLabel: 'Maryland Today Article with image',\n});\n\n/**\n * Create announcer message\n *\n * @param offset - Current offset\n * @param total - Total entries\n * @param isLazyLoad - Lazy load enabled\n * @returns Announcer message\n */\nconst createAnnouncerMessage = (\n offset: number,\n total: number,\n isLazyLoad: boolean,\n): string => {\n return isLazyLoad\n ? `Showing ${offset} of ${total} articles`\n : `Showing ${offset} articles`;\n};\n\n// ============================================================================\n// STATE MANAGER CLASS\n// ============================================================================\n\n/**\n * Manages featured feed state and shadow DOM synchronization\n *\n * Encapsulates all mutable state including pagination, offset,\n * and shadow DOM management.\n */\nclass FeaturedFeedState {\n private stylesArray: string[] = [];\n private shadowRoot: ShadowRoot | null = null;\n private totalEntries: number = 0;\n private offset: number = 0;\n private hasRenderedOffset: boolean = false;\n private pagination: PaginationState | 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 * Set offset to specific value\n *\n * @param value - New offset value\n */\n setOffset(value: number): void {\n this.offset = value;\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 * Check if offset layout has been rendered\n *\n * @returns True if offset layout rendered\n */\n hasOffset(): boolean {\n return this.hasRenderedOffset;\n }\n\n /**\n * Mark offset layout as rendered\n */\n markOffsetRendered(): void {\n this.hasRenderedOffset = true;\n }\n\n /**\n * Get pagination state\n *\n * @returns Pagination state or null\n */\n getPagination(): PaginationState | null {\n return this.pagination;\n }\n\n /**\n * Set pagination state\n *\n * @param pagination - Pagination state\n */\n setPagination(pagination: PaginationState | null): void {\n this.pagination = pagination;\n }\n}\n\n// ============================================================================\n// RENDERING FUNCTIONS\n// ============================================================================\n\n/**\n * Create overlay card for featured entry\n *\n * @param entry - News entry\n * @param state - State manager\n * @param isThemeDark - Dark theme flag\n * @returns Overlay card element model\n */\nconst createOverlayCard = (\n entry: NewsEntry,\n state: FeaturedFeedState,\n isThemeDark: boolean,\n): ElementModel => {\n const overlayCard = newsDisplayStrategy.mapEntryToCard(entry, {\n isOverlay: true,\n isThemeDark,\n imageConfig: () => createImageConfig(entry),\n });\n\n // Add custom overlay styles\n state.addStyles(`\n ${overlayCard.styles}\n\n .${card.overlay.imageClassRef} {\n height: inherit;\n }\n\n .${card.overlay.imageClassRef} .umd-asset-image-wrapper-scaled {\n position: absolute;\n }\n `);\n\n return overlayCard;\n};\n\n/**\n * Create block cards for entries\n *\n * @param entries - News entries\n * @param state - State manager\n * @param options - Card options\n * @returns Array of block card element models\n */\nconst createBlockCards = (\n entries: NewsEntry[],\n state: FeaturedFeedState,\n options: { isThemeDark: boolean; isTransparent: boolean },\n): ElementModel[] => {\n return entries.map((entry) => {\n const blockCard = newsDisplayStrategy.mapEntryToCard(entry, {\n isThemeDark: options.isThemeDark,\n isTransparent: options.isTransparent,\n isAligned: true,\n imageConfig: () => createImageConfig(entry),\n });\n\n state.addStyles(blockCard.styles);\n return blockCard;\n });\n};\n\n/**\n * Render featured layout (initial load only)\n *\n * @param container - Container element\n * @param entries - News entries\n * @param state - State manager\n * @param props - Feed props\n * @param loadMore - Load more callback\n * @returns Promise that resolves when rendering is complete\n */\nconst renderFeaturedLayout = async (\n container: HTMLElement,\n entries: NewsEntry[],\n state: FeaturedFeedState,\n props: FeaturedProps,\n loadMore: () => Promise<void>,\n): Promise<void> => {\n const {\n isThemeDark = false,\n isTransparent = false,\n isLayoutReversed = false,\n overwriteStickyPosition,\n isLazyLoad = false,\n } = props;\n\n // Fall back to standard grid if not enough entries or already rendered\n if (entries.length < 2 || state.hasOffset()) {\n return renderStandardGrid(container, entries, state, {\n isThemeDark,\n isTransparent,\n });\n }\n\n state.markOffsetRendered();\n\n // Create offset layout\n const offsetLayout = gridOffset({\n columns: 2,\n isLayoutReversed,\n stickyTopPosition: overwriteStickyPosition,\n });\n\n // Create grid for remaining items\n const gridLayout = gridGap({ columns: 2 });\n gridLayout.element.setAttribute('id', 'umd-featured-news-grid-container');\n\n // First item: overlay card\n const overlayCard = createOverlayCard(entries[0], state, isThemeDark);\n\n // Next 2 items: block cards\n const blockCards = createBlockCards(entries.slice(1, 3), state, {\n isThemeDark,\n isTransparent,\n });\n\n // Append block cards to grid\n blockCards.forEach((card) => {\n gridLayout.element.appendChild(card.element);\n });\n\n // Assemble offset layout\n offsetLayout.element.appendChild(overlayCard.element);\n offsetLayout.element.appendChild(gridLayout.element);\n container.appendChild(offsetLayout.element);\n\n state.addStyles(offsetLayout.styles);\n state.addStyles(gridLayout.styles);\n state.setOffset(3); // We've shown 3 items\n\n // Add pagination if needed\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) state.addStyles(paginationElement.styles);\n state.setPagination(pagination);\n }\n\n // Announcer\n const message = createAnnouncerMessage(\n INITIAL_ITEMS,\n state.getTotalEntries(),\n isLazyLoad,\n );\n const announcer = new Announcer({ message });\n container.appendChild(announcer.getElement());\n\n await state.updateShadowStyles();\n};\n\n/**\n * Render standard grid (for lazy-loaded items or fallback)\n *\n * @param container - Container element\n * @param entries - News entries\n * @param state - State manager\n * @param options - Rendering options\n * @returns Promise that resolves when rendering is complete\n */\nconst renderStandardGrid = async (\n container: HTMLElement,\n entries: NewsEntry[],\n state: FeaturedFeedState,\n options: { isThemeDark: boolean; isTransparent: boolean },\n): Promise<void> => {\n let gridContainer = container.querySelector(\n '#umd-featured-news-grid-container',\n ) as HTMLElement;\n\n // Create grid if it doesn't exist\n if (!gridContainer) {\n const gridLayout = gridGap({ columns: 2 });\n gridLayout.element.setAttribute('id', 'umd-featured-news-grid-container');\n container.appendChild(gridLayout.element);\n state.addStyles(gridLayout.styles);\n gridContainer = gridLayout.element;\n }\n\n // Create and append block cards\n const blockCards = createBlockCards(entries, state, options);\n blockCards.forEach((card) => {\n gridContainer.appendChild(card.element);\n });\n\n state.incrementOffset(entries.length);\n\n await state.updateShadowStyles();\n};\n\n/**\n * Render error state\n *\n * @param container - Container element\n * @param message - Error message\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 message: string,\n state: FeaturedFeedState,\n isThemeDark: boolean,\n): Promise<void> => {\n const emptyState = new EmptyState({ message, isThemeDark });\n emptyState.render(container);\n state.addStyles(emptyState.styles);\n await state.updateShadowStyles();\n};\n\n// ============================================================================\n// MAIN EXPORT\n// ============================================================================\n\n/**\n * Create a featured news feed\n *\n * Displays news with featured layout: overlay card + grid.\n * Uses Element Builder pattern for clean construction.\n *\n * @param props - Feed configuration\n * @returns ElementModel with feed element, styles, and events\n *\n * @example\n * ```typescript\n * const feed = newsFeatured({\n * token: 'my-token',\n * isLazyLoad: true,\n * });\n * ```\n *\n * @example\n * ```typescript\n * // With custom sticky position\n * const feed = newsFeatured({\n * token: 'my-token',\n * overwriteStickyPosition: 100,\n * isLayoutReversed: true,\n * });\n * ```\n */\nexport const newsFeatured = (props: FeaturedProps): ElementModel => {\n const {\n token,\n categories,\n isUnion,\n isThemeDark = false,\n isLazyLoad = false,\n isTransparent = false,\n } = props;\n\n // Create container using ElementBuilder\n const containerBuilder = new ElementBuilder('div').withClassName(\n 'featured-news-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 FeaturedFeedState(loading.styles);\n\n /**\n * Load more articles (for lazy loading)\n */\n const loadMore = async (): Promise<void> => {\n // Remove pagination button\n const pagination = state.getPagination();\n if (pagination) {\n pagination.remove();\n }\n\n // Show loading indicator\n loading.show(container);\n\n // Load more items\n const fetchProps = createFetchProps(\n { token, categories, isUnion },\n state.getOffset(),\n );\n const variables = newsFetchStrategy.composeApiVariables(fetchProps);\n\n const entries = await newsFetchStrategy.fetchEntries(variables);\n\n // Hide loading indicator\n loading.hide();\n\n if (!entries || entries.length === 0) return;\n\n await renderStandardGrid(container, entries, state, {\n isThemeDark,\n isTransparent,\n });\n\n // Update pagination state\n if (pagination) {\n pagination.updateState(state.getOffset(), state.getTotalEntries());\n if (pagination.styles) state.addStyles(pagination.styles);\n await state.updateShadowStyles();\n }\n\n // Update announcer\n const existingAnnouncer = container.querySelector(\n '[role=\"status\"]',\n ) as HTMLElement;\n if (existingAnnouncer) {\n existingAnnouncer.textContent = createAnnouncerMessage(\n state.getOffset(),\n state.getTotalEntries(),\n isLazyLoad,\n );\n }\n\n // Dispatch update event\n eventUtilities.dispatch(\n container,\n eventUtilities.eventNames.FEED_LOADED_MORE,\n {\n items: entries,\n count: entries.length,\n total: state.getTotalEntries(),\n },\n );\n };\n\n /**\n * Initialize feed\n */\n const initialize = async (): Promise<void> => {\n loading.show(container);\n\n // Fetch initial items\n const fetchProps = createFetchProps({ token, categories, isUnion }, 0);\n const variables = newsFetchStrategy.composeApiVariables(fetchProps);\n\n const [count, entries] = await Promise.all([\n newsFetchStrategy.fetchCount(variables),\n newsFetchStrategy.fetchEntries(variables),\n ]);\n\n loading.hide();\n\n // Handle no results\n if (!entries || entries.length === 0) {\n await renderError(\n container,\n 'No news articles found',\n state,\n isThemeDark,\n );\n return;\n }\n\n state.setTotalEntries(count || entries.length);\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 featured layout\n await renderFeaturedLayout(container, entries, state, props, loadMore);\n };\n\n // Start initialization\n initialize();\n\n // Build and return element model\n const model = containerBuilder.build();\n\n // Custom event: allow external control of sticky position\n const setPosition = (position: number) => {\n const overlayElement = container.querySelector(\n `.${card.overlay.imageClassRef}`,\n ) as HTMLElement;\n if (overlayElement) overlayElement.style.top = `${position}px`;\n };\n\n return {\n element: model.element,\n get styles() {\n return state.getStyles();\n },\n events: {\n callback: state.getShadowCallback(),\n setPosition, // Custom event for sticky position control\n },\n };\n};\n"],"names":["styleUtilities.setShadowStyles","card","eventUtilities.dispatch","eventUtilities.eventNames"],"mappings":"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"}
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import { BlockProps } from './_types';
|
|
2
2
|
import { ElementModel } from '../../_types';
|
|
3
|
-
declare const
|
|
4
|
-
export default _default;
|
|
3
|
+
export declare const newsGrid: (props: BlockProps) => ElementModel;
|
|
5
4
|
//# sourceMappingURL=grid.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"grid.d.ts","sourceRoot":"","sources":["../../../source/feeds/news/grid.ts"],"names":[],"mappings":"AAgBA,OAAO,EAAE,KAAK,UAAU,EAAE,MAAM,UAAU,CAAC;AAC3C,OAAO,EAAE,KAAK,YAAY,EAAE,MAAM,cAAc,CAAC;
|
|
1
|
+
{"version":3,"file":"grid.d.ts","sourceRoot":"","sources":["../../../source/feeds/news/grid.ts"],"names":[],"mappings":"AAgBA,OAAO,EAAE,KAAK,UAAU,EAAE,MAAM,UAAU,CAAC;AAC3C,OAAO,EAAE,KAAK,YAAY,EAAE,MAAM,cAAc,CAAC;AA6BjD,eAAO,MAAM,QAAQ,GAAI,OAAO,UAAU,KAAG,YAiB5C,CAAC"}
|
package/dist/feeds/news/grid.js
CHANGED
|
@@ -1,29 +1,28 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
const grid = (props) => {
|
|
1
|
+
import { createBaseFeed } from "../../factory/core/createBaseFeed.js";
|
|
2
|
+
import "@universityofmaryland/web-builder-library";
|
|
3
|
+
import "@universityofmaryland/web-styles-library";
|
|
4
|
+
import "@universityofmaryland/web-styles-library/typography";
|
|
5
|
+
import "@universityofmaryland/web-utilities-library/theme";
|
|
6
|
+
import "@universityofmaryland/web-elements-library";
|
|
7
|
+
import "@universityofmaryland/web-elements-library/composite";
|
|
8
|
+
import "@universityofmaryland/web-elements-library/atomic";
|
|
9
|
+
import "@universityofmaryland/web-utilities-library/elements";
|
|
10
|
+
import { newsDisplayStrategy } from "../../strategies/display/news.js";
|
|
11
|
+
import "@universityofmaryland/web-utilities-library/network";
|
|
12
|
+
import "../../strategies/fetch/events.js";
|
|
13
|
+
import { newsFetchStrategy } from "../../strategies/fetch/news.js";
|
|
14
|
+
import "../../strategies/fetch/experts.js";
|
|
15
|
+
import { gridLayout, gridGapLayout } from "../../strategies/layout/grid.js";
|
|
16
|
+
import "@universityofmaryland/web-elements-library/layout";
|
|
17
|
+
const newsGrid = (props) => {
|
|
19
18
|
const { isTypeOverlay = false } = props;
|
|
20
|
-
return createBaseFeed
|
|
19
|
+
return createBaseFeed({
|
|
21
20
|
...props,
|
|
22
21
|
isOverlay: isTypeOverlay,
|
|
23
22
|
isAligned: !isTypeOverlay,
|
|
24
|
-
fetchStrategy:
|
|
25
|
-
displayStrategy:
|
|
26
|
-
layoutStrategy: isTypeOverlay ?
|
|
23
|
+
fetchStrategy: newsFetchStrategy,
|
|
24
|
+
displayStrategy: newsDisplayStrategy,
|
|
25
|
+
layoutStrategy: isTypeOverlay ? gridLayout : gridGapLayout,
|
|
27
26
|
imageConfig: (entry) => ({
|
|
28
27
|
imageUrl: entry.image[0].url,
|
|
29
28
|
altText: entry.image[0].altText || "News Article Image",
|
|
@@ -32,5 +31,7 @@ const grid = (props) => {
|
|
|
32
31
|
})
|
|
33
32
|
});
|
|
34
33
|
};
|
|
35
|
-
|
|
34
|
+
export {
|
|
35
|
+
newsGrid
|
|
36
|
+
};
|
|
36
37
|
//# sourceMappingURL=grid.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"grid.js","sources":["../../../source/feeds/news/grid.ts"],"sourcesContent":["/**\n * News Grid Feed (Factory Pattern)\n *\n * Grid layout for news article entries using the feed factory pattern.\n * This is the NEW implementation using factory + strategies.\n *\n * @module composite/news/grid-new\n */\n\nimport { createBaseFeed } from 'factory';\nimport {\n newsFetchStrategy,\n newsDisplayStrategy,\n gridLayout,\n gridGapLayout,\n} from 'strategies';\nimport { type BlockProps } from './_types';\nimport { type ElementModel } from '../../_types';\n\n/**\n * Create a news 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 gap\n * const feed = newsGrid({\n * token: 'my-token',\n * numberOfColumnsToShow: 3,\n * numberOfRowsToStart: 2,\n * isLazyLoad: true,\n * });\n *\n * // Overlay grid\n * const overlayFeed = newsGrid({\n * token: 'my-token',\n * numberOfColumnsToShow: 3,\n * numberOfRowsToStart: 2,\n * isTypeOverlay: true,\n * });\n *\n * document.body.appendChild(feed.element);\n * ```\n */\nexport
|
|
1
|
+
{"version":3,"file":"grid.js","sources":["../../../source/feeds/news/grid.ts"],"sourcesContent":["/**\n * News Grid Feed (Factory Pattern)\n *\n * Grid layout for news article entries using the feed factory pattern.\n * This is the NEW implementation using factory + strategies.\n *\n * @module composite/news/grid-new\n */\n\nimport { createBaseFeed } from 'factory';\nimport {\n newsFetchStrategy,\n newsDisplayStrategy,\n gridLayout,\n gridGapLayout,\n} from 'strategies';\nimport { type BlockProps } from './_types';\nimport { type ElementModel } from '../../_types';\n\n/**\n * Create a news 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 gap\n * const feed = newsGrid({\n * token: 'my-token',\n * numberOfColumnsToShow: 3,\n * numberOfRowsToStart: 2,\n * isLazyLoad: true,\n * });\n *\n * // Overlay grid\n * const overlayFeed = newsGrid({\n * token: 'my-token',\n * numberOfColumnsToShow: 3,\n * numberOfRowsToStart: 2,\n * isTypeOverlay: true,\n * });\n *\n * document.body.appendChild(feed.element);\n * ```\n */\nexport const newsGrid = (props: BlockProps): ElementModel => {\n const { isTypeOverlay = false } = props;\n\n return createBaseFeed({\n ...props,\n isOverlay: isTypeOverlay,\n isAligned: !isTypeOverlay,\n fetchStrategy: newsFetchStrategy,\n displayStrategy: newsDisplayStrategy,\n layoutStrategy: isTypeOverlay ? gridLayout : gridGapLayout,\n imageConfig: (entry) => ({\n imageUrl: entry.image[0].url,\n altText: entry.image[0].altText || 'News Article Image',\n linkUrl: entry.url,\n linkLabel: 'Maryland Today Article with image',\n }),\n });\n};\n"],"names":[],"mappings":";;;;;;;;;;;;;;;;AA8CO,MAAM,WAAW,CAAC,UAAoC;AAC3D,QAAM,EAAE,gBAAgB,MAAA,IAAU;AAElC,SAAO,eAAe;AAAA,IACpB,GAAG;AAAA,IACH,WAAW;AAAA,IACX,WAAW,CAAC;AAAA,IACZ,eAAe;AAAA,IACf,iBAAiB;AAAA,IACjB,gBAAgB,gBAAgB,aAAa;AAAA,IAC7C,aAAa,CAAC,WAAW;AAAA,MACvB,UAAU,MAAM,MAAM,CAAC,EAAE;AAAA,MACzB,SAAS,MAAM,MAAM,CAAC,EAAE,WAAW;AAAA,MACnC,SAAS,MAAM;AAAA,MACf,WAAW;AAAA,IAAA;AAAA,EACb,CACD;AACH;"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export {
|
|
2
|
-
export {
|
|
3
|
-
export {
|
|
1
|
+
export { newsFeatured as featured } from './featured';
|
|
2
|
+
export { newsGrid as grid } from './grid';
|
|
3
|
+
export { newsList as list } from './list';
|
|
4
4
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../source/feeds/news/index.ts"],"names":[],"mappings":"AAqBA,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../source/feeds/news/index.ts"],"names":[],"mappings":"AAqBA,OAAO,EAAE,YAAY,IAAI,QAAQ,EAAE,MAAM,YAAY,CAAC;AAqBtD,OAAO,EAAE,QAAQ,IAAI,IAAI,EAAE,MAAM,QAAQ,CAAC;AAoB1C,OAAO,EAAE,QAAQ,IAAI,IAAI,EAAE,MAAM,QAAQ,CAAC"}
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import { ListProps } from './_types';
|
|
2
2
|
import { ElementModel } from '../../_types';
|
|
3
|
-
declare const
|
|
4
|
-
export default _default;
|
|
3
|
+
export declare const newsList: (props: ListProps) => ElementModel;
|
|
5
4
|
//# sourceMappingURL=list.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"list.d.ts","sourceRoot":"","sources":["../../../source/feeds/news/list.ts"],"names":[],"mappings":"AAeA,OAAO,EAAE,KAAK,SAAS,EAAE,MAAM,UAAU,CAAC;AAC1C,OAAO,EAAE,KAAK,YAAY,EAAE,MAAM,cAAc,CAAC;
|
|
1
|
+
{"version":3,"file":"list.d.ts","sourceRoot":"","sources":["../../../source/feeds/news/list.ts"],"names":[],"mappings":"AAeA,OAAO,EAAE,KAAK,SAAS,EAAE,MAAM,UAAU,CAAC;AAC1C,OAAO,EAAE,KAAK,YAAY,EAAE,MAAM,cAAc,CAAC;AAoBjD,eAAO,MAAM,QAAQ,GAAI,OAAO,SAAS,KAAG,YAcxC,CAAC"}
|
package/dist/feeds/news/list.js
CHANGED
|
@@ -1,27 +1,26 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
const list = (props) => createBaseFeed.createBaseFeed({
|
|
1
|
+
import { createBaseFeed } from "../../factory/core/createBaseFeed.js";
|
|
2
|
+
import "@universityofmaryland/web-builder-library";
|
|
3
|
+
import "@universityofmaryland/web-styles-library";
|
|
4
|
+
import "@universityofmaryland/web-styles-library/typography";
|
|
5
|
+
import "@universityofmaryland/web-utilities-library/theme";
|
|
6
|
+
import "@universityofmaryland/web-elements-library";
|
|
7
|
+
import "@universityofmaryland/web-elements-library/composite";
|
|
8
|
+
import "@universityofmaryland/web-elements-library/atomic";
|
|
9
|
+
import "@universityofmaryland/web-utilities-library/elements";
|
|
10
|
+
import { newsDisplayStrategy } from "../../strategies/display/news.js";
|
|
11
|
+
import "@universityofmaryland/web-utilities-library/network";
|
|
12
|
+
import "../../strategies/fetch/events.js";
|
|
13
|
+
import { newsFetchStrategy } from "../../strategies/fetch/news.js";
|
|
14
|
+
import "../../strategies/fetch/experts.js";
|
|
15
|
+
import { stackedLayout } from "../../strategies/layout/grid.js";
|
|
16
|
+
import "@universityofmaryland/web-elements-library/layout";
|
|
17
|
+
const newsList = (props) => createBaseFeed({
|
|
19
18
|
...props,
|
|
20
19
|
cardType: "list",
|
|
21
20
|
isAligned: false,
|
|
22
|
-
fetchStrategy:
|
|
23
|
-
displayStrategy:
|
|
24
|
-
layoutStrategy:
|
|
21
|
+
fetchStrategy: newsFetchStrategy,
|
|
22
|
+
displayStrategy: newsDisplayStrategy,
|
|
23
|
+
layoutStrategy: stackedLayout,
|
|
25
24
|
imageConfig: (entry) => ({
|
|
26
25
|
imageUrl: entry.image[0].url,
|
|
27
26
|
altText: entry.image[0].altText || "News Article Image",
|
|
@@ -29,5 +28,7 @@ const list = (props) => createBaseFeed.createBaseFeed({
|
|
|
29
28
|
linkLabel: "Maryland Today Article with image"
|
|
30
29
|
})
|
|
31
30
|
});
|
|
32
|
-
|
|
31
|
+
export {
|
|
32
|
+
newsList
|
|
33
|
+
};
|
|
33
34
|
//# sourceMappingURL=list.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"list.js","sources":["../../../source/feeds/news/list.ts"],"sourcesContent":["/**\n * News List Feed (Factory Pattern)\n *\n * List layout for news article entries using the feed factory pattern.\n * This is the NEW implementation using factory + strategies.\n *\n * @module composite/news/list-new\n */\n\nimport { createBaseFeed } from 'factory';\nimport {\n newsFetchStrategy,\n newsDisplayStrategy,\n stackedLayout,\n} from 'strategies';\nimport { type ListProps } from './_types';\nimport { type ElementModel } from '../../_types';\n\n/**\n * Create a news list feed\n *\n * @param props - Feed configuration\n * @returns ElementModel with feed element and styles\n *\n * @example\n * ```typescript\n * const feed = newsList({\n * token: 'my-token',\n * numberOfRowsToStart: 5,\n * isLazyLoad: true,\n * categories: ['research', 'campus-life'],\n * });\n *\n * document.body.appendChild(feed.element);\n * ```\n */\nexport
|
|
1
|
+
{"version":3,"file":"list.js","sources":["../../../source/feeds/news/list.ts"],"sourcesContent":["/**\n * News List Feed (Factory Pattern)\n *\n * List layout for news article entries using the feed factory pattern.\n * This is the NEW implementation using factory + strategies.\n *\n * @module composite/news/list-new\n */\n\nimport { createBaseFeed } from 'factory';\nimport {\n newsFetchStrategy,\n newsDisplayStrategy,\n stackedLayout,\n} from 'strategies';\nimport { type ListProps } from './_types';\nimport { type ElementModel } from '../../_types';\n\n/**\n * Create a news list feed\n *\n * @param props - Feed configuration\n * @returns ElementModel with feed element and styles\n *\n * @example\n * ```typescript\n * const feed = newsList({\n * token: 'my-token',\n * numberOfRowsToStart: 5,\n * isLazyLoad: true,\n * categories: ['research', 'campus-life'],\n * });\n *\n * document.body.appendChild(feed.element);\n * ```\n */\nexport const newsList = (props: ListProps): ElementModel =>\n createBaseFeed({\n ...props,\n cardType: 'list',\n isAligned: false,\n fetchStrategy: newsFetchStrategy,\n displayStrategy: newsDisplayStrategy,\n layoutStrategy: stackedLayout,\n imageConfig: (entry) => ({\n imageUrl: entry.image[0].url,\n altText: entry.image[0].altText || 'News Article Image',\n linkUrl: entry.url,\n linkLabel: 'Maryland Today Article with image',\n }),\n });\n"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAoCO,MAAM,WAAW,CAAC,UACvB,eAAe;AAAA,EACb,GAAG;AAAA,EACH,UAAU;AAAA,EACV,WAAW;AAAA,EACX,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,5 +1,3 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
3
1
|
const eventNames = {
|
|
4
2
|
/** Triggered when a feed has finished loading its content */
|
|
5
3
|
FEED_LOADED: "feed:loaded",
|
|
@@ -16,6 +14,8 @@ const dispatch = (element, eventName, detail) => {
|
|
|
16
14
|
});
|
|
17
15
|
return element.dispatchEvent(event);
|
|
18
16
|
};
|
|
19
|
-
|
|
20
|
-
|
|
17
|
+
export {
|
|
18
|
+
dispatch,
|
|
19
|
+
eventNames
|
|
20
|
+
};
|
|
21
21
|
//# sourceMappingURL=index.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sources":["../../../source/helpers/events/index.ts"],"sourcesContent":["/**\n * Event names supported by the feeds library.\n * These can be used for consistent event handling across implementations.\n */\nexport const eventNames = {\n /** Triggered when a feed has finished loading its content */\n FEED_LOADED: 'feed:loaded',\n\n /** Triggered when a feed loads more content (lazy loading/pagination) */\n FEED_LOADED_MORE: 'feed:loaded:more',\n\n /** Triggered when an error occurs during feed loading or processing */\n FEED_ERROR: 'feed:error',\n};\n\n/**\n * Custom event details for different feed events.\n */\nexport interface FeedEventDetails {\n /** Items in the feed that have been loaded */\n items?: any[];\n\n /** Error information if a feed failed to load */\n error?: Error | string;\n\n /** Information about a specific item that was clicked */\n item?: any;\n\n /** Additional custom data that may be included with any event */\n [key: string]: any;\n}\n\n/**\n * Dispatches a custom feed event on the specified element.\n *\n * @param element - The element to dispatch the event on\n * @param eventName - Name of the event to dispatch (use eventNames constants for consistency)\n * @param detail - Event details to include\n * @returns True if the event was dispatched successfully and not cancelled\n *\n * @example\n * ```typescript\n * import { events } from '@universityofmaryland/web-feeds-library/utilities';\n *\n * // Dispatch a feed loaded event\n * events.dispatch(feedContainer, events.eventNames.FEED_LOADED, { items: loadedItems });\n *\n * // Listen for feed loaded events\n * feedContainer.addEventListener(events.eventNames.FEED_LOADED, (event) => {\n * console.log('Feed loaded with', event.detail.items.length, 'items');\n * });\n * ```\n */\nexport const dispatch = (\n element: HTMLElement,\n eventName: string,\n detail: FeedEventDetails,\n): boolean => {\n const event = new CustomEvent(eventName, {\n detail,\n bubbles: true,\n cancelable: true,\n });\n\n return element.dispatchEvent(event);\n};\n\n/**\n * Adds an event listener for a specific feed event with proper TypeScript typings for the event detail.\n *\n * @param element - The element to attach the event listener to\n * @param eventName - Name of the event to listen for (use eventNames constants for consistency)\n * @param callback - Function to call when the event is triggered\n * @param options - Standard addEventListener options (capture, once, passive, etc.)\n * @returns A function that removes the event listener when called\n *\n * @example\n * ```typescript\n * import { events } from '@universityofmaryland/web-feeds-library/utilities';\n *\n * // Add a typed event listener\n * const removeListener = events.listen(\n * feedContainer,\n * events.eventNames.FEED_LOADED,\n * (detail) => console.log('Feed loaded with', detail.items.length, 'items')\n * );\n *\n * // Later, if needed:\n * removeListener();\n * ```\n */\nexport const listen = (\n element: HTMLElement,\n eventName: string,\n callback: (detail: FeedEventDetails) => void,\n options?: AddEventListenerOptions,\n): (() => void) => {\n const eventListener = (event: Event) => {\n const customEvent = event as CustomEvent<FeedEventDetails>;\n callback(customEvent.detail);\n };\n\n element.addEventListener(eventName, eventListener, options);\n\n return () => {\n element.removeEventListener(eventName, eventListener, options);\n };\n};\n"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.js","sources":["../../../source/helpers/events/index.ts"],"sourcesContent":["/**\n * Event names supported by the feeds library.\n * These can be used for consistent event handling across implementations.\n */\nexport const eventNames = {\n /** Triggered when a feed has finished loading its content */\n FEED_LOADED: 'feed:loaded',\n\n /** Triggered when a feed loads more content (lazy loading/pagination) */\n FEED_LOADED_MORE: 'feed:loaded:more',\n\n /** Triggered when an error occurs during feed loading or processing */\n FEED_ERROR: 'feed:error',\n};\n\n/**\n * Custom event details for different feed events.\n */\nexport interface FeedEventDetails {\n /** Items in the feed that have been loaded */\n items?: any[];\n\n /** Error information if a feed failed to load */\n error?: Error | string;\n\n /** Information about a specific item that was clicked */\n item?: any;\n\n /** Additional custom data that may be included with any event */\n [key: string]: any;\n}\n\n/**\n * Dispatches a custom feed event on the specified element.\n *\n * @param element - The element to dispatch the event on\n * @param eventName - Name of the event to dispatch (use eventNames constants for consistency)\n * @param detail - Event details to include\n * @returns True if the event was dispatched successfully and not cancelled\n *\n * @example\n * ```typescript\n * import { events } from '@universityofmaryland/web-feeds-library/utilities';\n *\n * // Dispatch a feed loaded event\n * events.dispatch(feedContainer, events.eventNames.FEED_LOADED, { items: loadedItems });\n *\n * // Listen for feed loaded events\n * feedContainer.addEventListener(events.eventNames.FEED_LOADED, (event) => {\n * console.log('Feed loaded with', event.detail.items.length, 'items');\n * });\n * ```\n */\nexport const dispatch = (\n element: HTMLElement,\n eventName: string,\n detail: FeedEventDetails,\n): boolean => {\n const event = new CustomEvent(eventName, {\n detail,\n bubbles: true,\n cancelable: true,\n });\n\n return element.dispatchEvent(event);\n};\n\n/**\n * Adds an event listener for a specific feed event with proper TypeScript typings for the event detail.\n *\n * @param element - The element to attach the event listener to\n * @param eventName - Name of the event to listen for (use eventNames constants for consistency)\n * @param callback - Function to call when the event is triggered\n * @param options - Standard addEventListener options (capture, once, passive, etc.)\n * @returns A function that removes the event listener when called\n *\n * @example\n * ```typescript\n * import { events } from '@universityofmaryland/web-feeds-library/utilities';\n *\n * // Add a typed event listener\n * const removeListener = events.listen(\n * feedContainer,\n * events.eventNames.FEED_LOADED,\n * (detail) => console.log('Feed loaded with', detail.items.length, 'items')\n * );\n *\n * // Later, if needed:\n * removeListener();\n * ```\n */\nexport const listen = (\n element: HTMLElement,\n eventName: string,\n callback: (detail: FeedEventDetails) => void,\n options?: AddEventListenerOptions,\n): (() => void) => {\n const eventListener = (event: Event) => {\n const customEvent = event as CustomEvent<FeedEventDetails>;\n callback(customEvent.detail);\n };\n\n element.addEventListener(eventName, eventListener, options);\n\n return () => {\n element.removeEventListener(eventName, eventListener, options);\n };\n};\n"],"names":[],"mappings":"AAIO,MAAM,aAAa;AAAA;AAAA,EAExB,aAAa;AAAA;AAAA,EAGb,kBAAkB;AAAA;AAAA,EAGlB,YAAY;AACd;AAwCO,MAAM,WAAW,CACtB,SACA,WACA,WACY;AACZ,QAAM,QAAQ,IAAI,YAAY,WAAW;AAAA,IACvC;AAAA,IACA,SAAS;AAAA,IACT,YAAY;AAAA,EAAA,CACb;AAED,SAAO,QAAQ,cAAc,KAAK;AACpC;"}
|