dce-reactkit 3.1.4 → 3.1.7

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.
@@ -0,0 +1,17 @@
1
+ /**
2
+ * Reusable nested item picker
3
+ * @author Yuen Ler Chow
4
+ */
5
+ import React from 'react';
6
+ import PickableItem from './types/PickableItem';
7
+ declare type Props = {
8
+ items: PickableItem[];
9
+ /**
10
+ * Handler to call when item selection is changed
11
+ * @param updatedItems an updated copy of the list of items with checked
12
+ * values updated
13
+ */
14
+ onChanged: (updatedItems: PickableItem[]) => void;
15
+ };
16
+ declare const NestableItemList: React.FC<Props>;
17
+ export default NestableItemList;
@@ -0,0 +1,18 @@
1
+ /**
2
+ * Reusable nested item picker
3
+ * @author Yuen Ler Chow
4
+ */
5
+ import React from 'react';
6
+ import PickableItem from './types/PickableItem';
7
+ declare type Props = {
8
+ title: string;
9
+ items: PickableItem[];
10
+ /**
11
+ * Handler to call when item selection is changed
12
+ * @param updatedItems an updated copy of the list of items with checked
13
+ * values updated
14
+ */
15
+ onChanged: (updatedItems: PickableItem[]) => void;
16
+ };
17
+ declare const ItemPicker: React.FC<Props>;
18
+ export default ItemPicker;
@@ -0,0 +1,16 @@
1
+ /**
2
+ * An item that can be chosen (for use within ItemPicker)
3
+ * @author Gabe Abrams
4
+ */
5
+ declare type PickableItem = ({
6
+ id: number | string;
7
+ name: string;
8
+ link?: string;
9
+ } & ({
10
+ isGroup: false;
11
+ checked: boolean;
12
+ } | {
13
+ isGroup: true;
14
+ children: PickableItem[];
15
+ }));
16
+ export default PickableItem;
@@ -0,0 +1,12 @@
1
+ /**
2
+ * Run tasks in parallel with a limit on how many tasks can execute at once.
3
+ * No guarantees are made about the order of task execution
4
+ * @author Gabe Abrams
5
+ * @param taskFunctions functions that start asynchronous tasks and optionally
6
+ * resolve with values
7
+ * @param [limit=no limit] maximum number of asynchronous tasks to permit to run at
8
+ * once
9
+ * @returns array of resolved values in the same order as the task functions
10
+ */
11
+ declare const parallelLimit: (taskFunctions: (() => Promise<any>)[], limit?: number | undefined) => Promise<any[]>;
12
+ export default parallelLimit;
@@ -12,6 +12,7 @@ import PopSuccessMark from './components/PopSuccessMark';
12
12
  import PopFailureMark from './components/PopFailureMark';
13
13
  import PopPendingMark from './components/PopPendingMark';
14
14
  import CopiableBox from './components/CopiableBox';
15
+ import ItemPicker from './components/ItemPicker';
15
16
  import ErrorWithCode from './errors/ErrorWithCode';
16
17
  import MINUTE_IN_MS from './constants/MINUTE_IN_MS';
17
18
  import HOUR_IN_MS from './constants/HOUR_IN_MS';
@@ -39,6 +40,7 @@ import getHumanReadableDate from './helpers/getHumanReadableDate';
39
40
  import getPartOfDay from './helpers/getPartOfDay';
40
41
  import stringsToHumanReadableList from './helpers/stringsToHumanReadableList';
41
42
  import onlyKeepLetters from './helpers/onlyKeepLetters';
43
+ import parallelLimit from './helpers/parallelLimit';
42
44
  import ModalButtonType from './types/ModalButtonType';
43
45
  import ModalSize from './types/ModalSize';
44
46
  import ModalType from './types/ModalType';
@@ -46,4 +48,4 @@ import ReactKitErrorCode from './types/ReactKitErrorCode';
46
48
  import Variant from './types/Variant';
47
49
  import ParamType from './types/ParamType';
48
50
  import DayOfWeek from './types/DayOfWeek';
49
- export { AppWrapper, LoadingSpinner, ErrorBox, Modal, TabBox, RadioButton, CheckboxButton, ButtonInputGroup, SimpleDateChooser, Drawer, PopSuccessMark, PopFailureMark, PopPendingMark, CopiableBox, alert, confirm, showFatalError, ErrorWithCode, MINUTE_IN_MS, HOUR_IN_MS, DAY_IN_MS, abbreviate, avg, ceilToNumDecimals, floorToNumDecimals, forceNumIntoBounds, padDecimalZeros, padZerosLeft, roundToNumDecimals, sum, waitMs, getOrdinal, getTimeInfoInET, stubServerEndpoint, startMinWait, getHumanReadableDate, getPartOfDay, stringsToHumanReadableList, onlyKeepLetters, visitServerEndpoint, initServer, genRouteHandler, handleError, handleSuccess, ModalButtonType, ModalSize, ModalType, ReactKitErrorCode, Variant, DayOfWeek, ParamType, };
51
+ export { AppWrapper, LoadingSpinner, ErrorBox, Modal, TabBox, RadioButton, CheckboxButton, ButtonInputGroup, SimpleDateChooser, Drawer, PopSuccessMark, PopFailureMark, PopPendingMark, CopiableBox, ItemPicker, alert, confirm, showFatalError, ErrorWithCode, MINUTE_IN_MS, HOUR_IN_MS, DAY_IN_MS, abbreviate, avg, ceilToNumDecimals, floorToNumDecimals, forceNumIntoBounds, padDecimalZeros, padZerosLeft, roundToNumDecimals, sum, waitMs, getOrdinal, getTimeInfoInET, stubServerEndpoint, startMinWait, getHumanReadableDate, getPartOfDay, stringsToHumanReadableList, onlyKeepLetters, parallelLimit, visitServerEndpoint, initServer, genRouteHandler, handleError, handleSuccess, ModalButtonType, ModalSize, ModalType, ReactKitErrorCode, Variant, DayOfWeek, ParamType, };
package/dist/esm/index.js CHANGED
@@ -1,6 +1,6 @@
1
1
  import React, { useState, useRef, useEffect, useReducer } from 'react';
2
2
  import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
3
- import { faExclamationTriangle, faCircle, faDotCircle, faCheckSquare, faHourglass, faClipboard } from '@fortawesome/free-solid-svg-icons';
3
+ import { faExclamationTriangle, faCircle, faDotCircle, faCheckSquare, faHourglass, faClipboard, faChevronDown, faChevronRight } from '@fortawesome/free-solid-svg-icons';
4
4
  import { faCircle as faCircle$1, faSquareMinus, faSquare } from '@fortawesome/free-regular-svg-icons';
5
5
 
6
6
  /******************************************************************************
@@ -1535,27 +1535,27 @@ const PopPendingMark = (props) => {
1535
1535
  */
1536
1536
  /* ------------- Actions ------------ */
1537
1537
  // Types of actions
1538
- var ActionType;
1538
+ var ActionType$1;
1539
1539
  (function (ActionType) {
1540
1540
  // Indicate that the text was recently copied
1541
1541
  ActionType["IndicateRecentlyCopied"] = "indicate-recently-copied";
1542
1542
  // Clear the status
1543
1543
  ActionType["ClearRecentlyCopiedStatus"] = "clear-recently-copied-status";
1544
- })(ActionType || (ActionType = {}));
1544
+ })(ActionType$1 || (ActionType$1 = {}));
1545
1545
  /**
1546
1546
  * Reducer that executes actions
1547
1547
  * @author Gabe Abrams
1548
1548
  * @param state current state
1549
1549
  * @param action action to execute
1550
1550
  */
1551
- const reducer = (state, action) => {
1551
+ const reducer$1 = (state, action) => {
1552
1552
  switch (action.type) {
1553
- case ActionType.IndicateRecentlyCopied: {
1553
+ case ActionType$1.IndicateRecentlyCopied: {
1554
1554
  return {
1555
1555
  recentlyCopied: true,
1556
1556
  };
1557
1557
  }
1558
- case ActionType.ClearRecentlyCopiedStatus: {
1558
+ case ActionType$1.ClearRecentlyCopiedStatus: {
1559
1559
  return {
1560
1560
  recentlyCopied: false,
1561
1561
  };
@@ -1581,7 +1581,7 @@ const CopiableBox = (props) => {
1581
1581
  recentlyCopied: false,
1582
1582
  };
1583
1583
  // Initialize state
1584
- const [state, dispatch] = useReducer(reducer, initialState);
1584
+ const [state, dispatch] = useReducer(reducer$1, initialState);
1585
1585
  // Destructure common state
1586
1586
  const { recentlyCopied, } = state;
1587
1587
  /*------------------------------------------------------------------------*/
@@ -1601,13 +1601,13 @@ const CopiableBox = (props) => {
1601
1601
  }
1602
1602
  // Show copied notice
1603
1603
  dispatch({
1604
- type: ActionType.IndicateRecentlyCopied,
1604
+ type: ActionType$1.IndicateRecentlyCopied,
1605
1605
  });
1606
1606
  // Wait a moment
1607
1607
  yield waitMs(4000);
1608
1608
  // Hide copied notice
1609
1609
  dispatch({
1610
- type: ActionType.ClearRecentlyCopiedStatus,
1610
+ type: ActionType$1.ClearRecentlyCopiedStatus,
1611
1611
  });
1612
1612
  });
1613
1613
  /*------------------------------------------------------------------------*/
@@ -1656,6 +1656,183 @@ const CopiableBox = (props) => {
1656
1656
  "Copy")))));
1657
1657
  };
1658
1658
 
1659
+ /**
1660
+ * Reusable nested item picker
1661
+ * @author Yuen Ler Chow
1662
+ */
1663
+ /* ------------- Actions ------------ */
1664
+ // Types of actions
1665
+ var ActionType;
1666
+ (function (ActionType) {
1667
+ // Toggle whether the children are being shown
1668
+ ActionType["ToggleItems"] = "toggle-items";
1669
+ })(ActionType || (ActionType = {}));
1670
+ /**
1671
+ * Reducer that executes actions
1672
+ * @author Yuen Ler Chow
1673
+ * @param state current state
1674
+ * @param action action to execute
1675
+ */
1676
+ const reducer = (state, action) => {
1677
+ switch (action.type) {
1678
+ case ActionType.ToggleItems: {
1679
+ return { isShowingItems: !state.isShowingItems };
1680
+ }
1681
+ default: {
1682
+ return state;
1683
+ }
1684
+ }
1685
+ };
1686
+ /*------------------------------------------------------------------------*/
1687
+ /* Component */
1688
+ /*------------------------------------------------------------------------*/
1689
+ const NestableItemList = (props) => {
1690
+ /*------------------------------------------------------------------------*/
1691
+ /* Setup */
1692
+ /*------------------------------------------------------------------------*/
1693
+ /* -------------- Props ------------- */
1694
+ // Destructure all props
1695
+ const { items, onChanged, } = props;
1696
+ /* -------------- State ------------- */
1697
+ // Initial state
1698
+ const initialState = {
1699
+ isShowingItems: true,
1700
+ };
1701
+ // Initialize state
1702
+ const [state, dispatch] = useReducer(reducer, initialState);
1703
+ // Destructure common state
1704
+ const { isShowingItems, } = state;
1705
+ /*------------------------------------------------------------------------*/
1706
+ /* Component Functions */
1707
+ /*------------------------------------------------------------------------*/
1708
+ /**
1709
+ * Checks if all items in a list are checked
1710
+ * @author Yuen Ler Chow
1711
+ * @param pickableItems a list of items
1712
+ * @returns true if all items are checked. If any item is a group,
1713
+ * we recursively check its children
1714
+ */
1715
+ const allChecked = (pickableItems) => {
1716
+ return pickableItems.every((item) => {
1717
+ if (item.isGroup) {
1718
+ return allChecked(item.children);
1719
+ }
1720
+ return item.checked;
1721
+ });
1722
+ };
1723
+ /**
1724
+ * Checks if none of the items in a list are checked
1725
+ * @author Yuen Ler Chow
1726
+ * @param pickableItems a list of items
1727
+ * @returns true if all items are unchecked. If any item is a group, we
1728
+ * recursively check its children
1729
+ */
1730
+ const noneChecked = (pickableItems) => {
1731
+ return pickableItems.every((item) => {
1732
+ if (item.isGroup) {
1733
+ return noneChecked(item.children);
1734
+ }
1735
+ return !item.checked;
1736
+ });
1737
+ };
1738
+ /**
1739
+ * Change whether specific items are checked
1740
+ * @author Yuen Ler Chow
1741
+ * @param id the id of the item we want to check or uncheck OR true if
1742
+ * we are checking/unchecking all items, independent of their id
1743
+ * @param checked if true, the item will be checked.
1744
+ * @param pickableItems the list of items we iterate through to find the item
1745
+ * we want to check/uncheck
1746
+ * @returns a list of items with the item now checked/unchecked.
1747
+ * If it is a group, its children will also become checked/unchecked
1748
+ */
1749
+ const changeChecked = (id, checked, pickableItems) => {
1750
+ const updatedItems = pickableItems.map((item) => {
1751
+ if (item.id === id || id === true) {
1752
+ if (item.isGroup) {
1753
+ return Object.assign(Object.assign({}, item), { children: changeChecked(true, checked, item.children) });
1754
+ }
1755
+ return Object.assign(Object.assign({}, item), { checked });
1756
+ }
1757
+ if (item.isGroup) {
1758
+ return Object.assign(Object.assign({}, item), { children: changeChecked(id, checked, item.children) });
1759
+ }
1760
+ return item;
1761
+ });
1762
+ return updatedItems;
1763
+ };
1764
+ /**
1765
+ * Within a tree of items, swap in the list of updated items into the spot
1766
+ * indicated by the id
1767
+ * @author Yuen Ler Chow
1768
+ * @param id the id of the item group we want to change
1769
+ * @param updatedItems the list of items we want to change the items in the group to
1770
+ * @returns a list of all items containing the updated items
1771
+ */
1772
+ const changeItems = (id, updatedItems) => {
1773
+ return items.map((item) => {
1774
+ if (item.id === id) {
1775
+ return Object.assign(Object.assign({}, item), { children: updatedItems });
1776
+ }
1777
+ return item;
1778
+ });
1779
+ };
1780
+ /*------------------------------------------------------------------------*/
1781
+ /* Render */
1782
+ /*------------------------------------------------------------------------*/
1783
+ return (React.createElement("div", null, items.map((item) => {
1784
+ return (React.createElement("div", { key: item.id },
1785
+ React.createElement("span", { className: "NestableItemList-dropdown-button-container d-inline-block", style: {
1786
+ minWidth: '2rem',
1787
+ } }, item.isGroup && (React.createElement("button", { className: `NestableItemList-dropdown-button NestableItemList-dropdown-button-${item.id}`, style: {
1788
+ border: 0,
1789
+ backgroundColor: 'transparent',
1790
+ }, type: "button", onClick: () => {
1791
+ dispatch({
1792
+ type: ActionType.ToggleItems,
1793
+ });
1794
+ }, "aria-label": `${isShowingItems ? 'Hide' : 'Show'} items in ${item.name}` },
1795
+ React.createElement(FontAwesomeIcon, { icon: isShowingItems ? faChevronDown : faChevronRight })))),
1796
+ React.createElement(CheckboxButton, { className: `NestableItemList-CheckboxButton-${item.id}`, text: item.name, checked: item.isGroup ? allChecked(item.children) : item.checked, dashed: item.isGroup ? !noneChecked(item.children) : false, onChanged: (checked) => {
1797
+ onChanged(changeChecked(item.id, checked, items));
1798
+ }, ariaLabel: `Select ${item.name}`, checkedVariant: Variant$1.Light }),
1799
+ item.isGroup && isShowingItems && (React.createElement("div", { className: "NestableItemList-children-container", style: {
1800
+ paddingLeft: '2.2rem',
1801
+ } },
1802
+ React.createElement(NestableItemList, { items: item.children, onChanged: (updatedItems) => {
1803
+ onChanged(changeItems(item.id, updatedItems));
1804
+ } })))));
1805
+ })));
1806
+ };
1807
+
1808
+ /**
1809
+ * Reusable nested item picker
1810
+ * @author Yuen Ler Chow
1811
+ */
1812
+ /*------------------------------------------------------------------------*/
1813
+ /* Component */
1814
+ /*------------------------------------------------------------------------*/
1815
+ const ItemPicker = (props) => {
1816
+ /*------------------------------------------------------------------------*/
1817
+ /* Setup */
1818
+ /*------------------------------------------------------------------------*/
1819
+ /* -------------- Props ------------- */
1820
+ // Destructure all props
1821
+ const { title, items, onChanged, } = props;
1822
+ /*------------------------------------------------------------------------*/
1823
+ /* Component Functions */
1824
+ /*------------------------------------------------------------------------*/
1825
+ /*------------------------------------------------------------------------*/
1826
+ /* Render */
1827
+ /*------------------------------------------------------------------------*/
1828
+ /*----------------------------------------*/
1829
+ /* Main UI */
1830
+ /*----------------------------------------*/
1831
+ return (React.createElement(TabBox, { title: title },
1832
+ React.createElement("div", { style: { overflowX: 'scroll' } },
1833
+ React.createElement(NestableItemList, { items: items, onChanged: onChanged }))));
1834
+ };
1835
+
1659
1836
  /**
1660
1837
  * One minute in ms
1661
1838
  * @author Gabe Abrams
@@ -2481,6 +2658,55 @@ const onlyKeepLetters = (str) => {
2481
2658
  return str.replace(/[^a-zA-Z]+/g, '');
2482
2659
  };
2483
2660
 
2661
+ /**
2662
+ * Run tasks in parallel with a limit on how many tasks can execute at once.
2663
+ * No guarantees are made about the order of task execution
2664
+ * @author Gabe Abrams
2665
+ * @param taskFunctions functions that start asynchronous tasks and optionally
2666
+ * resolve with values
2667
+ * @param [limit=no limit] maximum number of asynchronous tasks to permit to run at
2668
+ * once
2669
+ * @returns array of resolved values in the same order as the task functions
2670
+ */
2671
+ const parallelLimit = (taskFunctions, limit) => __awaiter(void 0, void 0, void 0, function* () {
2672
+ const results = [];
2673
+ // Wait until finished with all tasks
2674
+ yield new Promise((resolve) => {
2675
+ /* ------------- Helpers ------------ */
2676
+ let nextTaskIndex = 0;
2677
+ let numFinishedTasks = 0;
2678
+ /**
2679
+ * Start the next task
2680
+ * @author Gabe Abrams
2681
+ */
2682
+ const startTask = () => __awaiter(void 0, void 0, void 0, function* () {
2683
+ const taskIndex = nextTaskIndex++;
2684
+ // Get the task
2685
+ const taskFunction = taskFunctions[taskIndex];
2686
+ if (!taskFunction) {
2687
+ return;
2688
+ }
2689
+ // Execute task
2690
+ const result = yield taskFunction();
2691
+ // Add results
2692
+ results[taskIndex] = result;
2693
+ // Tally and finish
2694
+ if (++numFinishedTasks === taskFunctions.length) {
2695
+ return resolve();
2696
+ }
2697
+ // Not finished! Start another task
2698
+ startTask();
2699
+ });
2700
+ /* ----------- Start Tasks ---------- */
2701
+ // If no limit, start all tasks. At least start 1 task
2702
+ const numTasks = Math.max((limit || taskFunctions.length), 1);
2703
+ for (let i = 0; i < numTasks; i++) {
2704
+ startTask();
2705
+ }
2706
+ });
2707
+ return results;
2708
+ });
2709
+
2484
2710
  /**
2485
2711
  * Days of the week
2486
2712
  * @author Gabe Abrams
@@ -2497,5 +2723,5 @@ var DayOfWeek;
2497
2723
  })(DayOfWeek || (DayOfWeek = {}));
2498
2724
  var DayOfWeek$1 = DayOfWeek;
2499
2725
 
2500
- export { AppWrapper, ButtonInputGroup, CheckboxButton, CopiableBox, DAY_IN_MS, DayOfWeek$1 as DayOfWeek, Drawer, ErrorBox, ErrorWithCode, HOUR_IN_MS, LoadingSpinner, MINUTE_IN_MS, Modal, ModalButtonType$1 as ModalButtonType, ModalSize$1 as ModalSize, ModalType$1 as ModalType, ParamType$1 as ParamType, PopFailureMark, PopPendingMark, PopSuccessMark, RadioButton, ReactKitErrorCode$1 as ReactKitErrorCode, SimpleDateChooser, TabBox, Variant$1 as Variant, abbreviate, alert$1 as alert, avg, ceilToNumDecimals, confirm, floorToNumDecimals, forceNumIntoBounds, genRouteHandler, getHumanReadableDate, getOrdinal, getPartOfDay, getTimeInfoInET, handleError, handleSuccess, initServer, onlyKeepLetters, padDecimalZeros, padZerosLeft, roundToNumDecimals, showFatalError, startMinWait, stringsToHumanReadableList, stubServerEndpoint, sum, visitServerEndpoint, waitMs };
2726
+ export { AppWrapper, ButtonInputGroup, CheckboxButton, CopiableBox, DAY_IN_MS, DayOfWeek$1 as DayOfWeek, Drawer, ErrorBox, ErrorWithCode, HOUR_IN_MS, ItemPicker, LoadingSpinner, MINUTE_IN_MS, Modal, ModalButtonType$1 as ModalButtonType, ModalSize$1 as ModalSize, ModalType$1 as ModalType, ParamType$1 as ParamType, PopFailureMark, PopPendingMark, PopSuccessMark, RadioButton, ReactKitErrorCode$1 as ReactKitErrorCode, SimpleDateChooser, TabBox, Variant$1 as Variant, abbreviate, alert$1 as alert, avg, ceilToNumDecimals, confirm, floorToNumDecimals, forceNumIntoBounds, genRouteHandler, getHumanReadableDate, getOrdinal, getPartOfDay, getTimeInfoInET, handleError, handleSuccess, initServer, onlyKeepLetters, padDecimalZeros, padZerosLeft, parallelLimit, roundToNumDecimals, showFatalError, startMinWait, stringsToHumanReadableList, stubServerEndpoint, sum, visitServerEndpoint, waitMs };
2501
2727
  //# sourceMappingURL=index.js.map