dce-reactkit 3.1.3 → 3.1.6

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/cjs/index.js CHANGED
@@ -937,7 +937,7 @@ const CheckboxButton = (props) => {
937
937
  /* Setup */
938
938
  /*------------------------------------------------------------------------*/
939
939
  /* -------------- Props ------------- */
940
- const { text, onChanged, ariaLabel, title, checked, id, noMarginOnRight, checkedVariant = Variant$1.Secondary, uncheckedVariant = Variant$1.Light, small, dashed, } = props;
940
+ const { text, onChanged, ariaLabel, title, checked, id, className, noMarginOnRight, checkedVariant = Variant$1.Secondary, uncheckedVariant = Variant$1.Light, small, dashed, } = props;
941
941
  /*------------------------------------------------------------------------*/
942
942
  /* Render */
943
943
  /*------------------------------------------------------------------------*/
@@ -955,7 +955,7 @@ const CheckboxButton = (props) => {
955
955
  : freeRegularSvgIcons.faSquare);
956
956
  }
957
957
  // Create the button
958
- return (React__default["default"].createElement("button", { type: "button", id: id, title: title, className: `CheckboxButton-status-${checked ? 'checked' : 'unchecked'} ${dashed ? 'CheckboxButton-dashed ' : ''}btn btn-${checked ? checkedVariant : uncheckedVariant}${checked ? ' selected' : ''}${small ? ' btn-sm' : ''} m-0${noMarginOnRight ? '' : ' me-1'}`, "aria-label": `${ariaLabel}${checked ? ': currently checked' : ''}`, onClick: () => {
958
+ return (React__default["default"].createElement("button", { type: "button", id: id, title: title, className: `CheckboxButton-status-${checked ? 'checked' : 'unchecked'} ${dashed ? 'CheckboxButton-dashed ' : ''}btn btn-${checked ? checkedVariant : uncheckedVariant}${checked ? ' selected' : ''}${small ? ' btn-sm' : ''} m-0${noMarginOnRight ? '' : ' me-1'} ${className !== null && className !== void 0 ? className : ''}`, "aria-label": `${ariaLabel}${checked ? ': currently checked' : ''}`, onClick: () => {
959
959
  onChanged(!checked);
960
960
  } },
961
961
  React__default["default"].createElement(reactFontawesome.FontAwesomeIcon, { icon: icon, className: "me-1" }),
@@ -1543,27 +1543,27 @@ const PopPendingMark = (props) => {
1543
1543
  */
1544
1544
  /* ------------- Actions ------------ */
1545
1545
  // Types of actions
1546
- var ActionType;
1546
+ var ActionType$1;
1547
1547
  (function (ActionType) {
1548
1548
  // Indicate that the text was recently copied
1549
1549
  ActionType["IndicateRecentlyCopied"] = "indicate-recently-copied";
1550
1550
  // Clear the status
1551
1551
  ActionType["ClearRecentlyCopiedStatus"] = "clear-recently-copied-status";
1552
- })(ActionType || (ActionType = {}));
1552
+ })(ActionType$1 || (ActionType$1 = {}));
1553
1553
  /**
1554
1554
  * Reducer that executes actions
1555
1555
  * @author Gabe Abrams
1556
1556
  * @param state current state
1557
1557
  * @param action action to execute
1558
1558
  */
1559
- const reducer = (state, action) => {
1559
+ const reducer$1 = (state, action) => {
1560
1560
  switch (action.type) {
1561
- case ActionType.IndicateRecentlyCopied: {
1561
+ case ActionType$1.IndicateRecentlyCopied: {
1562
1562
  return {
1563
1563
  recentlyCopied: true,
1564
1564
  };
1565
1565
  }
1566
- case ActionType.ClearRecentlyCopiedStatus: {
1566
+ case ActionType$1.ClearRecentlyCopiedStatus: {
1567
1567
  return {
1568
1568
  recentlyCopied: false,
1569
1569
  };
@@ -1589,7 +1589,7 @@ const CopiableBox = (props) => {
1589
1589
  recentlyCopied: false,
1590
1590
  };
1591
1591
  // Initialize state
1592
- const [state, dispatch] = React.useReducer(reducer, initialState);
1592
+ const [state, dispatch] = React.useReducer(reducer$1, initialState);
1593
1593
  // Destructure common state
1594
1594
  const { recentlyCopied, } = state;
1595
1595
  /*------------------------------------------------------------------------*/
@@ -1609,13 +1609,13 @@ const CopiableBox = (props) => {
1609
1609
  }
1610
1610
  // Show copied notice
1611
1611
  dispatch({
1612
- type: ActionType.IndicateRecentlyCopied,
1612
+ type: ActionType$1.IndicateRecentlyCopied,
1613
1613
  });
1614
1614
  // Wait a moment
1615
1615
  yield waitMs(4000);
1616
1616
  // Hide copied notice
1617
1617
  dispatch({
1618
- type: ActionType.ClearRecentlyCopiedStatus,
1618
+ type: ActionType$1.ClearRecentlyCopiedStatus,
1619
1619
  });
1620
1620
  });
1621
1621
  /*------------------------------------------------------------------------*/
@@ -1664,6 +1664,183 @@ const CopiableBox = (props) => {
1664
1664
  "Copy")))));
1665
1665
  };
1666
1666
 
1667
+ /**
1668
+ * Reusable nested item picker
1669
+ * @author Yuen Ler Chow
1670
+ */
1671
+ /* ------------- Actions ------------ */
1672
+ // Types of actions
1673
+ var ActionType;
1674
+ (function (ActionType) {
1675
+ // Toggle whether the children are being shown
1676
+ ActionType["ToggleItems"] = "toggle-items";
1677
+ })(ActionType || (ActionType = {}));
1678
+ /**
1679
+ * Reducer that executes actions
1680
+ * @author Yuen Ler Chow
1681
+ * @param state current state
1682
+ * @param action action to execute
1683
+ */
1684
+ const reducer = (state, action) => {
1685
+ switch (action.type) {
1686
+ case ActionType.ToggleItems: {
1687
+ return { isShowingItems: !state.isShowingItems };
1688
+ }
1689
+ default: {
1690
+ return state;
1691
+ }
1692
+ }
1693
+ };
1694
+ /*------------------------------------------------------------------------*/
1695
+ /* Component */
1696
+ /*------------------------------------------------------------------------*/
1697
+ const NestableItemList = (props) => {
1698
+ /*------------------------------------------------------------------------*/
1699
+ /* Setup */
1700
+ /*------------------------------------------------------------------------*/
1701
+ /* -------------- Props ------------- */
1702
+ // Destructure all props
1703
+ const { items, onChanged, } = props;
1704
+ /* -------------- State ------------- */
1705
+ // Initial state
1706
+ const initialState = {
1707
+ isShowingItems: true,
1708
+ };
1709
+ // Initialize state
1710
+ const [state, dispatch] = React.useReducer(reducer, initialState);
1711
+ // Destructure common state
1712
+ const { isShowingItems, } = state;
1713
+ /*------------------------------------------------------------------------*/
1714
+ /* Component Functions */
1715
+ /*------------------------------------------------------------------------*/
1716
+ /**
1717
+ * Checks if all items in a list are checked
1718
+ * @author Yuen Ler Chow
1719
+ * @param pickableItems a list of items
1720
+ * @returns true if all items are checked. If any item is a group,
1721
+ * we recursively check its children
1722
+ */
1723
+ const allChecked = (pickableItems) => {
1724
+ return pickableItems.every((item) => {
1725
+ if (item.isGroup) {
1726
+ return allChecked(item.children);
1727
+ }
1728
+ return item.checked;
1729
+ });
1730
+ };
1731
+ /**
1732
+ * Checks if none of the items in a list are checked
1733
+ * @author Yuen Ler Chow
1734
+ * @param pickableItems a list of items
1735
+ * @returns true if all items are unchecked. If any item is a group, we
1736
+ * recursively check its children
1737
+ */
1738
+ const noneChecked = (pickableItems) => {
1739
+ return pickableItems.every((item) => {
1740
+ if (item.isGroup) {
1741
+ return noneChecked(item.children);
1742
+ }
1743
+ return !item.checked;
1744
+ });
1745
+ };
1746
+ /**
1747
+ * Change whether specific items are checked
1748
+ * @author Yuen Ler Chow
1749
+ * @param id the id of the item we want to check or uncheck OR true if
1750
+ * we are checking/unchecking all items, independent of their id
1751
+ * @param checked if true, the item will be checked.
1752
+ * @param pickableItems the list of items we iterate through to find the item
1753
+ * we want to check/uncheck
1754
+ * @returns a list of items with the item now checked/unchecked.
1755
+ * If it is a group, its children will also become checked/unchecked
1756
+ */
1757
+ const changeChecked = (id, checked, pickableItems) => {
1758
+ const updatedItems = pickableItems.map((item) => {
1759
+ if (item.id === id || id === true) {
1760
+ if (item.isGroup) {
1761
+ return Object.assign(Object.assign({}, item), { children: changeChecked(true, checked, item.children) });
1762
+ }
1763
+ return Object.assign(Object.assign({}, item), { checked });
1764
+ }
1765
+ if (item.isGroup) {
1766
+ return Object.assign(Object.assign({}, item), { children: changeChecked(id, checked, item.children) });
1767
+ }
1768
+ return item;
1769
+ });
1770
+ return updatedItems;
1771
+ };
1772
+ /**
1773
+ * Within a tree of items, swap in the list of updated items into the spot
1774
+ * indicated by the id
1775
+ * @author Yuen Ler Chow
1776
+ * @param id the id of the item group we want to change
1777
+ * @param updatedItems the list of items we want to change the items in the group to
1778
+ * @returns a list of all items containing the updated items
1779
+ */
1780
+ const changeItems = (id, updatedItems) => {
1781
+ return items.map((item) => {
1782
+ if (item.id === id) {
1783
+ return Object.assign(Object.assign({}, item), { children: updatedItems });
1784
+ }
1785
+ return item;
1786
+ });
1787
+ };
1788
+ /*------------------------------------------------------------------------*/
1789
+ /* Render */
1790
+ /*------------------------------------------------------------------------*/
1791
+ return (React__default["default"].createElement("div", null, items.map((item) => {
1792
+ return (React__default["default"].createElement("div", { key: item.id },
1793
+ React__default["default"].createElement("span", { className: "NestableItemList-dropdown-button-container d-inline-block", style: {
1794
+ minWidth: '2rem',
1795
+ } }, item.isGroup && (React__default["default"].createElement("button", { className: `NestableItemList-dropdown-button NestableItemList-dropdown-button-${item.id}`, style: {
1796
+ border: 0,
1797
+ backgroundColor: 'transparent',
1798
+ }, type: "button", onClick: () => {
1799
+ dispatch({
1800
+ type: ActionType.ToggleItems,
1801
+ });
1802
+ }, "aria-label": `${isShowingItems ? 'Hide' : 'Show'} items in ${item.name}` },
1803
+ React__default["default"].createElement(reactFontawesome.FontAwesomeIcon, { icon: isShowingItems ? freeSolidSvgIcons.faChevronDown : freeSolidSvgIcons.faChevronRight })))),
1804
+ React__default["default"].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) => {
1805
+ onChanged(changeChecked(item.id, checked, items));
1806
+ }, ariaLabel: `Select ${item.name}`, checkedVariant: Variant$1.Light }),
1807
+ item.isGroup && isShowingItems && (React__default["default"].createElement("div", { className: "NestableItemList-children-container", style: {
1808
+ paddingLeft: '2.2rem',
1809
+ } },
1810
+ React__default["default"].createElement(NestableItemList, { items: item.children, onChanged: (updatedItems) => {
1811
+ onChanged(changeItems(item.id, updatedItems));
1812
+ } })))));
1813
+ })));
1814
+ };
1815
+
1816
+ /**
1817
+ * Reusable nested item picker
1818
+ * @author Yuen Ler Chow
1819
+ */
1820
+ /*------------------------------------------------------------------------*/
1821
+ /* Component */
1822
+ /*------------------------------------------------------------------------*/
1823
+ const ItemPicker = (props) => {
1824
+ /*------------------------------------------------------------------------*/
1825
+ /* Setup */
1826
+ /*------------------------------------------------------------------------*/
1827
+ /* -------------- Props ------------- */
1828
+ // Destructure all props
1829
+ const { title, items, onChanged, } = props;
1830
+ /*------------------------------------------------------------------------*/
1831
+ /* Component Functions */
1832
+ /*------------------------------------------------------------------------*/
1833
+ /*------------------------------------------------------------------------*/
1834
+ /* Render */
1835
+ /*------------------------------------------------------------------------*/
1836
+ /*----------------------------------------*/
1837
+ /* Main UI */
1838
+ /*----------------------------------------*/
1839
+ return (React__default["default"].createElement(TabBox, { title: title },
1840
+ React__default["default"].createElement("div", { style: { overflowX: 'scroll' } },
1841
+ React__default["default"].createElement(NestableItemList, { items: items, onChanged: onChanged }))));
1842
+ };
1843
+
1667
1844
  /**
1668
1845
  * One minute in ms
1669
1846
  * @author Gabe Abrams
@@ -2489,6 +2666,53 @@ const onlyKeepLetters = (str) => {
2489
2666
  return str.replace(/[^a-zA-Z]+/g, '');
2490
2667
  };
2491
2668
 
2669
+ /**
2670
+ * Run tasks in parallel with a limit on how many tasks can execute at once.
2671
+ * No guarantees are made about the order of task execution
2672
+ * @author Gabe Abrams
2673
+ * @param taskFunctions functions that start asynchronous tasks and optionally
2674
+ * resolve with values
2675
+ * @param limit maximum number of asynchronous tasks to permit to run at
2676
+ * once
2677
+ * @returns array of resolved values in the same order as the task functions
2678
+ */
2679
+ const parallelLimit = (taskFunctions, limit) => __awaiter(void 0, void 0, void 0, function* () {
2680
+ const results = [];
2681
+ // Wait until finished with all tasks
2682
+ yield new Promise((resolve) => {
2683
+ /* ------------- Helpers ------------ */
2684
+ let nextTaskIndex = 0;
2685
+ let numFinishedTasks = 0;
2686
+ /**
2687
+ * Start the next task
2688
+ * @author Gabe Abrams
2689
+ */
2690
+ const startTask = () => __awaiter(void 0, void 0, void 0, function* () {
2691
+ const taskIndex = nextTaskIndex++;
2692
+ // Get the task
2693
+ const taskFunction = taskFunctions[taskIndex];
2694
+ if (!taskFunction) {
2695
+ return;
2696
+ }
2697
+ // Execute task
2698
+ const result = yield taskFunction();
2699
+ // Add results
2700
+ results[taskIndex] = result;
2701
+ // Tally and finish
2702
+ if (++numFinishedTasks === taskFunctions.length) {
2703
+ return resolve();
2704
+ }
2705
+ // Not finished! Start another task
2706
+ startTask();
2707
+ });
2708
+ /* ----------- Start Tasks ---------- */
2709
+ for (let i = 0; i < limit; i++) {
2710
+ startTask();
2711
+ }
2712
+ });
2713
+ return results;
2714
+ });
2715
+
2492
2716
  /**
2493
2717
  * Days of the week
2494
2718
  * @author Gabe Abrams
@@ -2515,6 +2739,7 @@ exports.Drawer = Drawer;
2515
2739
  exports.ErrorBox = ErrorBox;
2516
2740
  exports.ErrorWithCode = ErrorWithCode;
2517
2741
  exports.HOUR_IN_MS = HOUR_IN_MS;
2742
+ exports.ItemPicker = ItemPicker;
2518
2743
  exports.LoadingSpinner = LoadingSpinner;
2519
2744
  exports.MINUTE_IN_MS = MINUTE_IN_MS;
2520
2745
  exports.Modal = Modal;
@@ -2548,6 +2773,7 @@ exports.initServer = initServer;
2548
2773
  exports.onlyKeepLetters = onlyKeepLetters;
2549
2774
  exports.padDecimalZeros = padDecimalZeros;
2550
2775
  exports.padZerosLeft = padZerosLeft;
2776
+ exports.parallelLimit = parallelLimit;
2551
2777
  exports.roundToNumDecimals = roundToNumDecimals;
2552
2778
  exports.showFatalError = showFatalError;
2553
2779
  exports.startMinWait = startMinWait;