@wise/dynamic-flow-client 5.13.3 → 5.14.0-experimental-76b77f2

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/build/main.mjs CHANGED
@@ -798,6 +798,7 @@ var getChildren = (node) => {
798
798
  return node.tabs.flatMap((c) => c.childrenProps);
799
799
  case "alert":
800
800
  case "button":
801
+ case "collection":
801
802
  case "input-checkbox":
802
803
  case "input-date":
803
804
  case "decision":
@@ -1356,6 +1357,305 @@ var boxLayoutToComponent = (uid, { border = false, components, control, margin,
1356
1357
  )
1357
1358
  });
1358
1359
 
1360
+ // src/domain/components/utils/debounce.ts
1361
+ var debounce = (callback, waitMs) => {
1362
+ let timeoutId = null;
1363
+ let lastArgs = null;
1364
+ const clearTimer = () => {
1365
+ if (timeoutId) {
1366
+ clearTimeout(timeoutId);
1367
+ timeoutId = null;
1368
+ }
1369
+ lastArgs = null;
1370
+ };
1371
+ const debouncedFn = (...args) => {
1372
+ lastArgs = args;
1373
+ if (timeoutId !== null) {
1374
+ clearTimeout(timeoutId);
1375
+ }
1376
+ timeoutId = setTimeout(() => {
1377
+ callback(...lastArgs);
1378
+ timeoutId = null;
1379
+ lastArgs = null;
1380
+ }, waitMs);
1381
+ };
1382
+ debouncedFn.cancel = () => {
1383
+ if (timeoutId !== null) {
1384
+ clearTimer();
1385
+ }
1386
+ };
1387
+ debouncedFn.flush = () => {
1388
+ if (timeoutId !== null) {
1389
+ callback(...lastArgs);
1390
+ clearTimer();
1391
+ }
1392
+ };
1393
+ return debouncedFn;
1394
+ };
1395
+
1396
+ // src/domain/components/CollectionComponent.ts
1397
+ var createCollectionComponent = (props, onComponentUpdate, searchFunction) => {
1398
+ const { uid, analyticsId, control, margin, tags, url, method, state, search, filters } = props;
1399
+ const update = getInputUpdateFunction(onComponentUpdate);
1400
+ let abortController = new AbortController();
1401
+ const searchFn = (component2, query, searchFilters, cursor) => {
1402
+ abortController.abort();
1403
+ abortController = new AbortController();
1404
+ const { signal } = abortController;
1405
+ searchFunction({
1406
+ query,
1407
+ cursor,
1408
+ signal,
1409
+ filters: searchFilters
1410
+ }).then((response) => {
1411
+ if (!response) {
1412
+ return;
1413
+ }
1414
+ if (response.type === "collection-content") {
1415
+ if (cursor) {
1416
+ update(component2, (draft) => {
1417
+ if (draft.state.type === "empty") {
1418
+ return;
1419
+ }
1420
+ const updated = draft.state.sections.map((section) => {
1421
+ const m = response.sections.find((s) => s.id === section.id);
1422
+ if (m) {
1423
+ return __spreadProps(__spreadValues({}, section), {
1424
+ items: [...section.items, ...m.items]
1425
+ });
1426
+ }
1427
+ return section;
1428
+ });
1429
+ draft.state.sections = updated;
1430
+ draft.state.nextCursor = response.nextCursor;
1431
+ draft.cursorStale = false;
1432
+ });
1433
+ } else {
1434
+ update(component2, (draft) => {
1435
+ draft.state = __spreadValues({}, response);
1436
+ draft.cursorStale = false;
1437
+ });
1438
+ }
1439
+ } else {
1440
+ update(component2, (draft) => {
1441
+ draft.state = response;
1442
+ });
1443
+ }
1444
+ }).catch(() => {
1445
+ });
1446
+ };
1447
+ const debouncedSearch = debounce(searchFn, 800);
1448
+ const component = {
1449
+ type: "collection",
1450
+ kind: "layout",
1451
+ uid,
1452
+ analyticsId,
1453
+ control,
1454
+ cursorStale: false,
1455
+ margin,
1456
+ method,
1457
+ url,
1458
+ tags,
1459
+ state,
1460
+ search: __spreadProps(__spreadValues({}, search), {
1461
+ onChange(query) {
1462
+ component._update((draft) => {
1463
+ draft.search.query = query;
1464
+ });
1465
+ debouncedSearch(component, query, component.filters);
1466
+ }
1467
+ }),
1468
+ filters: filters.map((filter, i) => {
1469
+ var _a;
1470
+ return __spreadProps(__spreadValues({}, filter), {
1471
+ options: (_a = filter.options) == null ? void 0 : _a.map((value, j) => {
1472
+ var _a2;
1473
+ return __spreadProps(__spreadValues({}, value), {
1474
+ selected: (_a2 = value.selected) != null ? _a2 : false,
1475
+ onSelect() {
1476
+ const currentValue = component.filters[i].options[j].selected;
1477
+ component._update((draft) => {
1478
+ if (filter.multiSelection) {
1479
+ draft.filters[i].options[j].selected = !currentValue;
1480
+ } else {
1481
+ draft.filters[i].options = draft.filters[i].options.map((option, k) => __spreadProps(__spreadValues({}, option), {
1482
+ selected: k === j ? !currentValue : false
1483
+ }));
1484
+ }
1485
+ });
1486
+ searchFn(component, component.search.query, component.filters, void 0);
1487
+ }
1488
+ });
1489
+ })
1490
+ });
1491
+ }),
1492
+ _update(updateFn) {
1493
+ update(this, updateFn);
1494
+ },
1495
+ loadMore() {
1496
+ if (this.cursorStale || this.state.type === "empty") {
1497
+ return;
1498
+ }
1499
+ const cursor = this.state.nextCursor;
1500
+ this._update((draft) => {
1501
+ draft.cursorStale = true;
1502
+ });
1503
+ searchFn(this, this.search.query, this.filters, cursor);
1504
+ }
1505
+ };
1506
+ return component;
1507
+ };
1508
+
1509
+ // src/domain/mappers/utils/utils.ts
1510
+ var mapInlineAlert = (alert) => {
1511
+ return alert ? {
1512
+ content: alert.content,
1513
+ context: alert.context ? mapLegacyContext(alert.context) : "neutral"
1514
+ } : void 0;
1515
+ };
1516
+ var mapAdditionalInfo = (info, mapperProps) => {
1517
+ const { onBehavior, registerSubmissionBehavior } = mapperProps;
1518
+ if (info) {
1519
+ const behavior = getDomainLayerBehavior(info, [], registerSubmissionBehavior);
1520
+ return {
1521
+ text: info.text,
1522
+ href: behavior.type === "link" ? behavior.url : void 0,
1523
+ accessibilityDescription: info.accessibilityDescription,
1524
+ onClick: behavior.type === "none" ? void 0 : () => {
1525
+ void onBehavior(behavior);
1526
+ }
1527
+ };
1528
+ }
1529
+ return void 0;
1530
+ };
1531
+ var mapSchemaAlert = (alert) => {
1532
+ return alert ? {
1533
+ content: alert.markdown,
1534
+ context: alert.context ? mapLegacyContext(alert.context) : "neutral"
1535
+ } : void 0;
1536
+ };
1537
+
1538
+ // src/domain/mappers/layout/collectionLayoutToComponent.ts
1539
+ var collectionLayoutToComponent = (uid, {
1540
+ analyticsId,
1541
+ control,
1542
+ filters,
1543
+ initialState,
1544
+ margin,
1545
+ method,
1546
+ search,
1547
+ tags,
1548
+ url
1549
+ }, mapperProps) => {
1550
+ const { httpClient, onComponentUpdate } = mapperProps;
1551
+ const searchFunction = getPerformCollectionSearchFunction(
1552
+ httpClient,
1553
+ url,
1554
+ method,
1555
+ search.param,
1556
+ mapperProps,
1557
+ (layout, index) => mapLayoutToComponent(`${uid}-collection-response-${index}`, layout, mapperProps, [])
1558
+ );
1559
+ const component = createCollectionComponent(
1560
+ {
1561
+ uid,
1562
+ analyticsId,
1563
+ control,
1564
+ margin: margin != null ? margin : "md",
1565
+ tags,
1566
+ url,
1567
+ method,
1568
+ state: {
1569
+ type: "collection-content",
1570
+ sections: initialState.sections.map((section) => {
1571
+ return {
1572
+ id: section.id,
1573
+ title: section.title,
1574
+ items: section.items.map((item) => {
1575
+ return __spreadProps(__spreadValues({}, item), {
1576
+ callToAction: getDomainLayerCallToAction(item.callToAction, mapperProps),
1577
+ inlineAlert: mapInlineAlert(item.inlineAlert)
1578
+ });
1579
+ })
1580
+ };
1581
+ }),
1582
+ nextCursor: initialState.nextCursor
1583
+ },
1584
+ search: {
1585
+ query: null,
1586
+ onChange(query) {
1587
+ }
1588
+ },
1589
+ filters: filters.filter((filter) => filter.options)
1590
+ },
1591
+ onComponentUpdate,
1592
+ searchFunction
1593
+ );
1594
+ return component;
1595
+ };
1596
+ var getPerformCollectionSearchFunction = (httpClient, url, method, searchParam, mapperProps, mapLayout) => {
1597
+ let latestSuccessfulRequestHash = "abc";
1598
+ let latestSuccessfulResults = null;
1599
+ return async ({ query, cursor, signal, filters }) => {
1600
+ const requestHash = query;
1601
+ const headers = { "Content-Type": "application/json" };
1602
+ const filterValues = filters.map(
1603
+ (f) => {
1604
+ var _a;
1605
+ return [f.param, (_a = f.options.find((option) => option.selected)) == null ? void 0 : _a.id];
1606
+ }
1607
+ );
1608
+ const response = await (method === "GET" ? httpClient(addQueryParameters(url, [[searchParam, query != null ? query : void 0], ...filterValues]), {
1609
+ method,
1610
+ headers,
1611
+ signal
1612
+ }) : httpClient(url, {
1613
+ method,
1614
+ headers,
1615
+ signal,
1616
+ body: JSON.stringify(__spreadValues(__spreadProps(__spreadValues({}, query ? { [searchParam]: query } : {}), {
1617
+ cursor
1618
+ }), filterValues.reduce((acc, [k, v]) => __spreadProps(__spreadValues({}, acc), { [k]: v }), {})))
1619
+ }));
1620
+ const results = await parseResponse(response);
1621
+ if (results.type === "collection-content") {
1622
+ return {
1623
+ type: "collection-content",
1624
+ sections: [
1625
+ ...results.sections.map((section) => __spreadProps(__spreadValues({}, section), {
1626
+ callToAction: getDomainLayerCallToAction(section.callToAction, mapperProps),
1627
+ items: section.items.map((item) => __spreadProps(__spreadValues({}, item), {
1628
+ callToAction: getDomainLayerCallToAction(item.callToAction, mapperProps),
1629
+ inlineAlert: mapInlineAlert(item.inlineAlert)
1630
+ }))
1631
+ }))
1632
+ ],
1633
+ nextCursor: results.nextCursor
1634
+ };
1635
+ }
1636
+ return {
1637
+ type: "empty",
1638
+ content: results.content.map(mapLayout)
1639
+ };
1640
+ };
1641
+ };
1642
+ var parseResponse = async (response) => {
1643
+ if (response.ok) {
1644
+ const body = await response.json().catch(() => null);
1645
+ return body;
1646
+ }
1647
+ throw Error("error response");
1648
+ };
1649
+ var addQueryParameters = (url, params) => {
1650
+ return params.reduce((u, [key, param]) => param ? addQueryParameter(u, key, param) : u, url);
1651
+ };
1652
+ var addQueryParameter = (url, key, value) => {
1653
+ const [urlBase, urlQuery] = url.split("?");
1654
+ const urlQueryParams = new URLSearchParams(urlQuery);
1655
+ urlQueryParams.set(key, value);
1656
+ return `${urlBase}?${urlQueryParams.toString()}`;
1657
+ };
1658
+
1359
1659
  // src/domain/components/ButtonComponent.ts
1360
1660
  var createButtonComponent = (buttonProps) => __spreadValues({
1361
1661
  type: "button",
@@ -1524,35 +1824,6 @@ var createDecisionComponent = (decisionProps) => __spreadValues({
1524
1824
  // src/domain/mappers/utils/tags-utils.ts
1525
1825
  var mapTags = ({ tag, tags }) => tags != null ? tags : tag != null ? [tag] : void 0;
1526
1826
 
1527
- // src/domain/mappers/utils/utils.ts
1528
- var mapInlineAlert = (alert) => {
1529
- return alert ? {
1530
- content: alert.content,
1531
- context: alert.context ? mapLegacyContext(alert.context) : "neutral"
1532
- } : void 0;
1533
- };
1534
- var mapAdditionalInfo = (info, mapperProps) => {
1535
- const { onBehavior, registerSubmissionBehavior } = mapperProps;
1536
- if (info) {
1537
- const behavior = getDomainLayerBehavior(info, [], registerSubmissionBehavior);
1538
- return {
1539
- text: info.text,
1540
- href: behavior.type === "link" ? behavior.url : void 0,
1541
- accessibilityDescription: info.accessibilityDescription,
1542
- onClick: behavior.type === "none" ? void 0 : () => {
1543
- void onBehavior(behavior);
1544
- }
1545
- };
1546
- }
1547
- return void 0;
1548
- };
1549
- var mapSchemaAlert = (alert) => {
1550
- return alert ? {
1551
- content: alert.markdown,
1552
- context: alert.context ? mapLegacyContext(alert.context) : "neutral"
1553
- } : void 0;
1554
- };
1555
-
1556
1827
  // src/domain/mappers/layout/decisionLayoutToComponent.ts
1557
1828
  var decisionLayoutToComponent = (uid, {
1558
1829
  analyticsId,
@@ -2023,42 +2294,6 @@ var mapReviewField = (field, mapperProps) => {
2023
2294
  });
2024
2295
  };
2025
2296
 
2026
- // src/domain/components/utils/debounce.ts
2027
- var debounce = (callback, waitMs) => {
2028
- let timeoutId = null;
2029
- let lastArgs = null;
2030
- const clearTimer = () => {
2031
- if (timeoutId) {
2032
- clearTimeout(timeoutId);
2033
- timeoutId = null;
2034
- }
2035
- lastArgs = null;
2036
- };
2037
- const debouncedFn = (...args) => {
2038
- lastArgs = args;
2039
- if (timeoutId !== null) {
2040
- clearTimeout(timeoutId);
2041
- }
2042
- timeoutId = setTimeout(() => {
2043
- callback(...lastArgs);
2044
- timeoutId = null;
2045
- lastArgs = null;
2046
- }, waitMs);
2047
- };
2048
- debouncedFn.cancel = () => {
2049
- if (timeoutId !== null) {
2050
- clearTimer();
2051
- }
2052
- };
2053
- debouncedFn.flush = () => {
2054
- if (timeoutId !== null) {
2055
- callback(...lastArgs);
2056
- clearTimer();
2057
- }
2058
- };
2059
- return debouncedFn;
2060
- };
2061
-
2062
2297
  // src/domain/components/searchComponent/SearchComponent.ts
2063
2298
  var DEBOUNCE_TIME = 400;
2064
2299
  var createSearchComponent = (searchProps, performSearch, onBehavior, onComponentUpdate) => {
@@ -2155,7 +2390,7 @@ var getPerformSearchFunction = (httpClient, mapLayoutToDomainComponent, defaultC
2155
2390
  if (requestHash !== latestSuccessfulRequestHash) {
2156
2391
  const { method, param, url } = config;
2157
2392
  const headers = { "Content-Type": "application/json" };
2158
- const response = await (method === "GET" ? httpClient(addQueryParameter(url, param, query), {
2393
+ const response = await (method === "GET" ? httpClient(addQueryParameter2(url, param, query), {
2159
2394
  method,
2160
2395
  headers,
2161
2396
  signal
@@ -2165,7 +2400,7 @@ var getPerformSearchFunction = (httpClient, mapLayoutToDomainComponent, defaultC
2165
2400
  signal,
2166
2401
  body: JSON.stringify({ [param]: query })
2167
2402
  }));
2168
- const results = await parseResponse(response);
2403
+ const results = await parseResponse2(response);
2169
2404
  latestSuccessfulRequestHash = requestHash;
2170
2405
  if (results.type === "layout") {
2171
2406
  const mappedLayoutResult = {
@@ -2181,7 +2416,7 @@ var getPerformSearchFunction = (httpClient, mapLayoutToDomainComponent, defaultC
2181
2416
  return latestSuccessfulResults;
2182
2417
  };
2183
2418
  };
2184
- var parseResponse = async (response) => {
2419
+ var parseResponse2 = async (response) => {
2185
2420
  if (response.ok) {
2186
2421
  const body = await response.json().catch(() => null);
2187
2422
  if (isValidResponseBody(body)) {
@@ -2198,7 +2433,7 @@ var parseResponse = async (response) => {
2198
2433
  }
2199
2434
  throw Error("error response");
2200
2435
  };
2201
- var addQueryParameter = (url, key, value) => {
2436
+ var addQueryParameter2 = (url, key, value) => {
2202
2437
  const [urlBase, urlQuery] = url.split("?");
2203
2438
  const urlQueryParams = new URLSearchParams(urlQuery);
2204
2439
  urlQueryParams.set(key, value);
@@ -2406,6 +2641,8 @@ var mapLayoutToComponent = (uid, layout, mapperProps, schemaComponents) => {
2406
2641
  return boxLayoutToComponent(uid, layout, mapperProps, schemaComponents);
2407
2642
  case "button":
2408
2643
  return buttonLayoutToComponent(uid, layout, mapperProps);
2644
+ case "collection":
2645
+ return collectionLayoutToComponent(uid, layout, mapperProps);
2409
2646
  case "columns":
2410
2647
  return columnsLayoutToComponent(uid, layout, mapperProps, schemaComponents);
2411
2648
  case "decision":
@@ -7421,6 +7658,34 @@ var mapBoxControl = ({
7421
7658
  return control;
7422
7659
  };
7423
7660
 
7661
+ // src/renderers/mappers/collectionComponentToProps.ts
7662
+ var collectionComponentToProps = (component, rendererMapperProps) => {
7663
+ var _a;
7664
+ return __spreadProps(__spreadValues(__spreadValues({}, pick(
7665
+ component,
7666
+ "uid",
7667
+ "analyticsId",
7668
+ "type",
7669
+ "control",
7670
+ "margin",
7671
+ "tags",
7672
+ "url",
7673
+ "method",
7674
+ "search",
7675
+ "filters"
7676
+ )), rendererMapperProps), {
7677
+ state: component.state.type === "empty" ? {
7678
+ type: "empty",
7679
+ children: component.state.content.map((child) => componentToRendererProps(child, rendererMapperProps)).map(rendererMapperProps.render)
7680
+ } : component.state,
7681
+ search: __spreadProps(__spreadValues({}, component.search), {
7682
+ query: (_a = component.search.query) != null ? _a : void 0
7683
+ }),
7684
+ filters: component.filters,
7685
+ loadMore: component.cursorStale ? void 0 : component.loadMore.bind(component)
7686
+ });
7687
+ };
7688
+
7424
7689
  // src/renderers/mappers/buttonComponentToProps.ts
7425
7690
  var buttonComponentToProps = (component, rendererMapperProps) => {
7426
7691
  return __spreadValues(__spreadProps(__spreadValues({
@@ -8245,6 +8510,8 @@ var getComponentProps = (component, rendererMapperProps) => {
8245
8510
  return boxComponentToProps(component, rendererMapperProps);
8246
8511
  case "button":
8247
8512
  return buttonComponentToProps(component, rendererMapperProps);
8513
+ case "collection":
8514
+ return collectionComponentToProps(component, rendererMapperProps);
8248
8515
  case "columns":
8249
8516
  return columnsComponentToProps(component, rendererMapperProps);
8250
8517
  case "container":