@trackunit/react-components 0.1.100 → 0.1.102

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/index.cjs CHANGED
@@ -10,6 +10,7 @@ var reactUse = require('react-use');
10
10
  var reactDayPicker = require('react-day-picker');
11
11
  var locale = require('date-fns/locale');
12
12
  var react = require('@floating-ui/react');
13
+ var lodash = require('lodash');
13
14
  var usePortal = require('react-useportal');
14
15
  var reactRouterDom = require('react-router-dom');
15
16
  var reactHelmetAsync = require('react-helmet-async');
@@ -1235,6 +1236,20 @@ function getDevicePixelRatio(options) {
1235
1236
  return rounded;
1236
1237
  }
1237
1238
 
1239
+ /**
1240
+ * Differentiate between the first and subsequent renders.
1241
+ *
1242
+ * @returns {boolean} Returns true if it is the first render, false otherwise.
1243
+ */
1244
+ const useIsFirstRender = () => {
1245
+ const renderRef = React.useRef(true);
1246
+ if (renderRef.current === true) {
1247
+ renderRef.current = false;
1248
+ return true;
1249
+ }
1250
+ return renderRef.current;
1251
+ };
1252
+
1238
1253
  /**
1239
1254
  * The useLocalStorage hook works like useState, but saves to localstorage.
1240
1255
  *
@@ -1278,6 +1293,50 @@ function tryParse(value) {
1278
1293
  }
1279
1294
  }
1280
1295
 
1296
+ /**
1297
+ * Given any value this hook will return the previous value whenever the current value changes
1298
+ */
1299
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
1300
+ function usePrevious(value) {
1301
+ const ref = React.useRef();
1302
+ React.useEffect(() => {
1303
+ ref.current = value;
1304
+ });
1305
+ return ref.current;
1306
+ }
1307
+ /**
1308
+ * Wraps a normal useReducer with local storage functionality
1309
+ *
1310
+ * @param {string} key - The key the state is saved with in local storage.
1311
+ */
1312
+ const useLocalStorageReducer = (key, reducer, initialState
1313
+ //return must be explicitly typed atm for some reason
1314
+ ) => {
1315
+ const init = () => {
1316
+ const stringState = localStorage.getItem(key);
1317
+ if (stringState) {
1318
+ try {
1319
+ return JSON.parse(stringState);
1320
+ }
1321
+ catch (error) {
1322
+ return initialState;
1323
+ }
1324
+ }
1325
+ else {
1326
+ return initialState;
1327
+ }
1328
+ };
1329
+ const [state, dispatch] = React.useReducer(reducer, initialState, init);
1330
+ const prevState = usePrevious(state);
1331
+ React.useEffect(() => {
1332
+ if (!lodash.isEqual(prevState, state)) {
1333
+ const stringifiedState = JSON.stringify(state);
1334
+ localStorage.setItem(key, stringifiedState);
1335
+ }
1336
+ }, [prevState, state, key]);
1337
+ return [state, dispatch];
1338
+ };
1339
+
1281
1340
  /**
1282
1341
  * Custom hook to handle window resize events and provide the current window size.
1283
1342
  *
@@ -1362,15 +1421,15 @@ const MoreMenu = ({ className, dataTestId, menuPlacement, iconProps = {
1362
1421
  circular: true,
1363
1422
  square: true,
1364
1423
  color: "tertiary",
1365
- }, children, }) => {
1424
+ }, customButton, children, }) => {
1366
1425
  const [actionMenuIsOpen, setActionMenuIsOpen] = React.useState(false);
1367
1426
  const actionMenuRef = React.useRef(null);
1368
1427
  useClickOutside(actionMenuRef, () => {
1369
1428
  setActionMenuIsOpen(false);
1370
1429
  });
1371
- return (jsxRuntime.jsx(Root$3, Object.assign({ ref: actionMenuRef, className: className, "data-testid": dataTestId }, { children: jsxRuntime.jsxs(Popover, Object.assign({ placement: menuPlacement }, { children: [jsxRuntime.jsx(PopoverTrigger, { children: jsxRuntime.jsx(IconButton, Object.assign({}, iconButtonProps, { icon: iconProps.name ? jsxRuntime.jsx(Icon, Object.assign({}, iconProps, { name: iconProps.name })) : null, onClick: () => {
1430
+ return (jsxRuntime.jsx(Root$3, Object.assign({ ref: actionMenuRef, className: className, "data-testid": dataTestId }, { children: jsxRuntime.jsxs(Popover, Object.assign({ placement: menuPlacement }, { children: [jsxRuntime.jsx(PopoverTrigger, { children: customButton !== null && customButton !== void 0 ? customButton : (jsxRuntime.jsx(IconButton, Object.assign({}, iconButtonProps, { icon: iconProps.name ? jsxRuntime.jsx(Icon, Object.assign({}, iconProps, { name: iconProps.name })) : null, onClick: () => {
1372
1431
  setActionMenuIsOpen(!actionMenuIsOpen);
1373
- } })) }), jsxRuntime.jsx(PopoverContent, { children: close => (typeof children === "function" ? children(close) : children) })] })) })));
1432
+ } }))) }), jsxRuntime.jsx(PopoverContent, { children: close => (typeof children === "function" ? children(close) : children) })] })) })));
1374
1433
  };
1375
1434
  const Root$3 = tailwindStyledComponents.tw.div `
1376
1435
  tu-more-menu
@@ -2244,7 +2303,9 @@ exports.useClickOutside = useClickOutside;
2244
2303
  exports.useContainerProps = useContainerProps;
2245
2304
  exports.useDebounce = useDebounce;
2246
2305
  exports.useDevicePixelRatio = useDevicePixelRatio;
2306
+ exports.useIsFirstRender = useIsFirstRender;
2247
2307
  exports.useLocalStorage = useLocalStorage;
2308
+ exports.useLocalStorageReducer = useLocalStorageReducer;
2248
2309
  exports.useModal = useModal;
2249
2310
  exports.usePopoverContext = usePopoverContext;
2250
2311
  exports.usePrompt = usePrompt;
package/index.js CHANGED
@@ -1,12 +1,13 @@
1
1
  import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
2
2
  import { tw, tws, twx } from '@trackunit/tailwind-styled-components';
3
3
  import * as React from 'react';
4
- import React__default, { useState, useMemo, createContext, useContext, forwardRef, isValidElement, cloneElement, useCallback, useEffect, Children, useRef, memo } from 'react';
4
+ import React__default, { useState, useMemo, createContext, useContext, forwardRef, isValidElement, cloneElement, useCallback, useEffect, Children, useRef, useReducer, memo } from 'react';
5
5
  import { HeroIconsArray, heroIconLookup, TrackunitSolidIconsArray, TrackunitOutlineIconsArray, trackunitIconLookup } from '@trackunit/ui-icons';
6
6
  import { useMeasure, useCopyToClipboard } from 'react-use';
7
7
  import { DayPicker as DayPicker$1 } from 'react-day-picker';
8
8
  import { enGB, enUS, da, de, cs, nl, fr, fi, hu, it, nb, pl, pt, ru, ro, es, sv, ja, th } from 'date-fns/locale';
9
9
  import { useFloating, autoUpdate, offset, flip, shift, size, useClick, useDismiss, useHover, useRole, useInteractions, useMergeRefs, FloatingPortal, FloatingFocusManager } from '@floating-ui/react';
10
+ import { isEqual } from 'lodash';
10
11
  import usePortal from 'react-useportal';
11
12
  import { UNSAFE_NavigationContext } from 'react-router-dom';
12
13
  import { HelmetProvider, Helmet } from 'react-helmet-async';
@@ -1208,6 +1209,20 @@ function getDevicePixelRatio(options) {
1208
1209
  return rounded;
1209
1210
  }
1210
1211
 
1212
+ /**
1213
+ * Differentiate between the first and subsequent renders.
1214
+ *
1215
+ * @returns {boolean} Returns true if it is the first render, false otherwise.
1216
+ */
1217
+ const useIsFirstRender = () => {
1218
+ const renderRef = useRef(true);
1219
+ if (renderRef.current === true) {
1220
+ renderRef.current = false;
1221
+ return true;
1222
+ }
1223
+ return renderRef.current;
1224
+ };
1225
+
1211
1226
  /**
1212
1227
  * The useLocalStorage hook works like useState, but saves to localstorage.
1213
1228
  *
@@ -1251,6 +1266,50 @@ function tryParse(value) {
1251
1266
  }
1252
1267
  }
1253
1268
 
1269
+ /**
1270
+ * Given any value this hook will return the previous value whenever the current value changes
1271
+ */
1272
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
1273
+ function usePrevious(value) {
1274
+ const ref = useRef();
1275
+ useEffect(() => {
1276
+ ref.current = value;
1277
+ });
1278
+ return ref.current;
1279
+ }
1280
+ /**
1281
+ * Wraps a normal useReducer with local storage functionality
1282
+ *
1283
+ * @param {string} key - The key the state is saved with in local storage.
1284
+ */
1285
+ const useLocalStorageReducer = (key, reducer, initialState
1286
+ //return must be explicitly typed atm for some reason
1287
+ ) => {
1288
+ const init = () => {
1289
+ const stringState = localStorage.getItem(key);
1290
+ if (stringState) {
1291
+ try {
1292
+ return JSON.parse(stringState);
1293
+ }
1294
+ catch (error) {
1295
+ return initialState;
1296
+ }
1297
+ }
1298
+ else {
1299
+ return initialState;
1300
+ }
1301
+ };
1302
+ const [state, dispatch] = useReducer(reducer, initialState, init);
1303
+ const prevState = usePrevious(state);
1304
+ useEffect(() => {
1305
+ if (!isEqual(prevState, state)) {
1306
+ const stringifiedState = JSON.stringify(state);
1307
+ localStorage.setItem(key, stringifiedState);
1308
+ }
1309
+ }, [prevState, state, key]);
1310
+ return [state, dispatch];
1311
+ };
1312
+
1254
1313
  /**
1255
1314
  * Custom hook to handle window resize events and provide the current window size.
1256
1315
  *
@@ -1335,15 +1394,15 @@ const MoreMenu = ({ className, dataTestId, menuPlacement, iconProps = {
1335
1394
  circular: true,
1336
1395
  square: true,
1337
1396
  color: "tertiary",
1338
- }, children, }) => {
1397
+ }, customButton, children, }) => {
1339
1398
  const [actionMenuIsOpen, setActionMenuIsOpen] = useState(false);
1340
1399
  const actionMenuRef = useRef(null);
1341
1400
  useClickOutside(actionMenuRef, () => {
1342
1401
  setActionMenuIsOpen(false);
1343
1402
  });
1344
- return (jsx(Root$3, Object.assign({ ref: actionMenuRef, className: className, "data-testid": dataTestId }, { children: jsxs(Popover, Object.assign({ placement: menuPlacement }, { children: [jsx(PopoverTrigger, { children: jsx(IconButton, Object.assign({}, iconButtonProps, { icon: iconProps.name ? jsx(Icon, Object.assign({}, iconProps, { name: iconProps.name })) : null, onClick: () => {
1403
+ return (jsx(Root$3, Object.assign({ ref: actionMenuRef, className: className, "data-testid": dataTestId }, { children: jsxs(Popover, Object.assign({ placement: menuPlacement }, { children: [jsx(PopoverTrigger, { children: customButton !== null && customButton !== void 0 ? customButton : (jsx(IconButton, Object.assign({}, iconButtonProps, { icon: iconProps.name ? jsx(Icon, Object.assign({}, iconProps, { name: iconProps.name })) : null, onClick: () => {
1345
1404
  setActionMenuIsOpen(!actionMenuIsOpen);
1346
- } })) }), jsx(PopoverContent, { children: close => (typeof children === "function" ? children(close) : children) })] })) })));
1405
+ } }))) }), jsx(PopoverContent, { children: close => (typeof children === "function" ? children(close) : children) })] })) })));
1347
1406
  };
1348
1407
  const Root$3 = tw.div `
1349
1408
  tu-more-menu
@@ -2155,4 +2214,4 @@ const Layout = tw.div `
2155
2214
  tu-layout-TwoColumnLayout
2156
2215
  `;
2157
2216
 
2158
- export { Alert, Badge, Button, Card, CardBody, CardFooter, CardHeader, Collapse, ContentGridArea, CopyableText, DayPicker, DayPickerPopover, DayRangePicker, DensityContainer, Drawer, ExternalLink, FilterListMapLayout, FullWidthRepeatingLayout, GridArea, Heading$1 as Heading, Icon, IconButton, Indicator, IntrinsicallyResponsiveGrid, MenuItem, MenuList, MinTopFullContentLayout, Modal, ModalBackdrop, MoreMenu, NavGridArea, PageHeader, Pagination, Popover, PopoverContent, PopoverTitle, PopoverTrigger, Prompt, ROLE_CARD, SectionHeader, Sidebar, SkeletonLines, Spacer, Spinner, StarButton, Tag, Text$1 as Text, Timeline, TimelineElement, Tip, TitleGridArea, TitleNavContentLayout, Tooltip, TwoColumnLayout, ValueBar, docs, getDevicePixelRatio, getValueBarColorByValue, useClickOutside, useContainerProps, useDebounce, useDevicePixelRatio, useLocalStorage, useModal, usePopoverContext, usePrompt, useResize, useTimeout };
2217
+ export { Alert, Badge, Button, Card, CardBody, CardFooter, CardHeader, Collapse, ContentGridArea, CopyableText, DayPicker, DayPickerPopover, DayRangePicker, DensityContainer, Drawer, ExternalLink, FilterListMapLayout, FullWidthRepeatingLayout, GridArea, Heading$1 as Heading, Icon, IconButton, Indicator, IntrinsicallyResponsiveGrid, MenuItem, MenuList, MinTopFullContentLayout, Modal, ModalBackdrop, MoreMenu, NavGridArea, PageHeader, Pagination, Popover, PopoverContent, PopoverTitle, PopoverTrigger, Prompt, ROLE_CARD, SectionHeader, Sidebar, SkeletonLines, Spacer, Spinner, StarButton, Tag, Text$1 as Text, Timeline, TimelineElement, Tip, TitleGridArea, TitleNavContentLayout, Tooltip, TwoColumnLayout, ValueBar, docs, getDevicePixelRatio, getValueBarColorByValue, useClickOutside, useContainerProps, useDebounce, useDevicePixelRatio, useIsFirstRender, useLocalStorage, useLocalStorageReducer, useModal, usePopoverContext, usePrompt, useResize, useTimeout };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@trackunit/react-components",
3
- "version": "0.1.100",
3
+ "version": "0.1.102",
4
4
  "repository": "https://github.com/Trackunit/manager",
5
5
  "license": "SEE LICENSE IN LICENSE.txt",
6
6
  "dependencies": {
@@ -10,6 +10,7 @@
10
10
  "@trackunit/ui-design-tokens": "0.0.66",
11
11
  "@trackunit/ui-icons": "0.0.64",
12
12
  "date-fns": "2.29.3",
13
+ "lodash": "4.17.21",
13
14
  "react": "18.2.0",
14
15
  "react-day-picker": "8.7.1",
15
16
  "react-dom": "18.2.0",
@@ -1,4 +1,4 @@
1
- /// <reference types="react" />
1
+ import { ReactNode } from "react";
2
2
  import { CommonProps } from "../../../common/CommonProps";
3
3
  import { IconButtonProps } from "../../buttons";
4
4
  import { IconProps } from "../../Icon/Icon";
@@ -11,6 +11,7 @@ export interface MoreMenuProps extends CommonProps {
11
11
  menuPlacement?: PopoverPlacement;
12
12
  iconProps?: FilteredIconProps;
13
13
  iconButtonProps?: FilteredIconButtonProps;
14
+ customButton?: ReactNode;
14
15
  }
15
16
  /**
16
17
  * A kebab menu component.
@@ -19,5 +20,5 @@ export interface MoreMenuProps extends CommonProps {
19
20
  * @param {MoreMenuProps} props - The props for the MoreMenu component
20
21
  * @returns {JSX.Element} MoreMenu component
21
22
  */
22
- export declare const MoreMenu: ({ className, dataTestId, menuPlacement, iconProps, iconButtonProps, children, }: MoreMenuProps) => JSX.Element;
23
+ export declare const MoreMenu: ({ className, dataTestId, menuPlacement, iconProps, iconButtonProps, customButton, children, }: MoreMenuProps) => JSX.Element;
23
24
  export {};
@@ -1,6 +1,8 @@
1
1
  export * from "./useClickOutside";
2
2
  export * from "./useDebounce";
3
3
  export * from "./useDevicePixelRatio";
4
+ export * from "./useIsFirstRender";
4
5
  export * from "./useLocalStorage";
6
+ export * from "./useLocalStorageReducer";
5
7
  export * from "./useResize";
6
8
  export * from "./useTimeout";
@@ -0,0 +1,6 @@
1
+ /**
2
+ * Differentiate between the first and subsequent renders.
3
+ *
4
+ * @returns {boolean} Returns true if it is the first render, false otherwise.
5
+ */
6
+ export declare const useIsFirstRender: () => boolean;
@@ -0,0 +1,7 @@
1
+ import { Dispatch } from "react";
2
+ /**
3
+ * Wraps a normal useReducer with local storage functionality
4
+ *
5
+ * @param {string} key - The key the state is saved with in local storage.
6
+ */
7
+ export declare const useLocalStorageReducer: <State, Action>(key: string, reducer: (state: State, action: Action) => State, initialState: State) => [State, Dispatch<Action>];