@ndlib/component-library 0.0.48 → 0.0.52

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.
Files changed (64) hide show
  1. package/dist/components/composites/DragDropList/DragDropList.stories.d.ts +7 -0
  2. package/dist/components/composites/DragDropList/DragDropList.stories.js +32 -0
  3. package/dist/components/composites/DragDropList/index.d.ts +23 -0
  4. package/dist/components/composites/DragDropList/index.js +46 -0
  5. package/dist/components/composites/DropdownLinks/index.js +3 -3
  6. package/dist/components/composites/Modal/Modal.stories.js +1 -1
  7. package/dist/components/composites/Seo/SeoDataDisplay/index.d.ts +2 -0
  8. package/dist/components/composites/Seo/SeoDataDisplay/index.js +9 -0
  9. package/dist/components/composites/Seo/index.d.ts +11 -0
  10. package/dist/components/composites/Seo/index.js +16 -0
  11. package/dist/components/composites/Seo/seo.stories.d.ts +6 -0
  12. package/dist/components/composites/Seo/seo.stories.js +12 -0
  13. package/dist/components/composites/Seo/seo.test.d.ts +1 -0
  14. package/dist/components/composites/Seo/seo.test.js +56 -0
  15. package/dist/components/composites/Seo/useSiteMetadata.d.ts +9 -0
  16. package/dist/components/composites/Seo/useSiteMetadata.js +16 -0
  17. package/dist/components/composites/SnackBar/SnackBar.stories.d.ts +8 -0
  18. package/dist/components/composites/SnackBar/SnackBar.stories.js +20 -0
  19. package/dist/components/composites/SnackBar/SnackBar.test.d.ts +1 -0
  20. package/dist/components/composites/SnackBar/SnackBar.test.js +75 -0
  21. package/dist/components/composites/SnackBar/examples.d.ts +3 -0
  22. package/dist/components/composites/SnackBar/examples.js +35 -0
  23. package/dist/components/composites/SnackBar/index.d.ts +1 -0
  24. package/dist/components/composites/SnackBar/index.js +45 -0
  25. package/dist/components/elements/Button/index.js +1 -1
  26. package/dist/components/elements/Fields/Select/index.js +6 -6
  27. package/dist/components/elements/Fields/TextInput/index.js +4 -4
  28. package/dist/components/elements/ListBox/index.d.ts +1 -1
  29. package/dist/components/elements/TabList/TabList.stories.d.ts +6 -0
  30. package/dist/components/elements/TabList/TabList.stories.js +12 -0
  31. package/dist/components/elements/TabList/TabList.test.d.ts +1 -0
  32. package/dist/components/elements/TabList/TabList.test.js +19 -0
  33. package/dist/components/elements/TabList/example.d.ts +7 -0
  34. package/dist/components/elements/TabList/example.js +36 -0
  35. package/dist/components/elements/TabList/index.d.ts +10 -0
  36. package/dist/components/elements/TabList/index.js +30 -0
  37. package/dist/components/elements/Table/Table.stories.d.ts +6 -0
  38. package/dist/components/elements/Table/Table.stories.js +42 -0
  39. package/dist/components/elements/Table/Table.test.d.ts +1 -0
  40. package/dist/components/elements/Table/Table.test.js +36 -0
  41. package/dist/components/elements/Table/index.d.ts +23 -0
  42. package/dist/components/elements/Table/index.js +47 -0
  43. package/dist/components/elements/layout/Box.d.ts +7 -2
  44. package/dist/components/elements/layout/Box.js +2 -3
  45. package/dist/components/elements/layout/Column.d.ts +7 -5
  46. package/dist/components/elements/layout/Column.js +4 -3
  47. package/dist/components/elements/layout/Row.d.ts +9 -7
  48. package/dist/components/elements/layout/Row.js +4 -3
  49. package/dist/components/providers/menu.js +3 -3
  50. package/dist/components/providers/snackBar.d.ts +23 -0
  51. package/dist/components/providers/snackBar.js +53 -0
  52. package/dist/components/providers/ui.js +3 -1
  53. package/dist/components/providers/uniqueIds.d.ts +3 -0
  54. package/dist/components/providers/uniqueIds.js +23 -0
  55. package/dist/components/providers/uniqueIds.test.d.ts +1 -0
  56. package/dist/components/providers/uniqueIds.test.js +26 -0
  57. package/dist/index.d.ts +8 -0
  58. package/dist/index.js +7 -0
  59. package/dist/theme/GlobalStyles.js +4 -5
  60. package/dist/theme/custom.d.ts +2 -2
  61. package/dist/theme/custom.js +2 -2
  62. package/package.json +8 -3
  63. package/dist/utils/hooks/useUniqueHtmlId.d.ts +0 -1
  64. package/dist/utils/hooks/useUniqueHtmlId.js +0 -7
@@ -0,0 +1,19 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import { render, fireEvent } from '@testing-library/react';
3
+ import { items, ExampleTabs } from './example';
4
+ describe('TabList', () => {
5
+ it('renders interactive tabs', () => {
6
+ const { getByRole } = render(_jsx(ExampleTabs, {}));
7
+ expect(getByRole('tablist')).toBeInTheDocument();
8
+ for (const item of items) {
9
+ expect(getByRole('tab', { name: item.label })).toBeInTheDocument();
10
+ }
11
+ const firstTab = getByRole('tab', { name: items[0].label });
12
+ const secondTab = getByRole('tab', { name: items[1].label });
13
+ expect(firstTab).toHaveAttribute('aria-selected', 'true');
14
+ expect(secondTab).toHaveAttribute('aria-selected', 'false');
15
+ fireEvent.click(secondTab);
16
+ expect(firstTab).toHaveAttribute('aria-selected', 'false');
17
+ expect(secondTab).toHaveAttribute('aria-selected', 'true');
18
+ });
19
+ });
@@ -0,0 +1,7 @@
1
+ type Item = {
2
+ id: string;
3
+ label: string;
4
+ };
5
+ export declare const items: Item[];
6
+ export declare const ExampleTabs: () => import("react/jsx-runtime").JSX.Element;
7
+ export {};
@@ -0,0 +1,36 @@
1
+ import { Fragment as _Fragment, jsx as _jsx } from "react/jsx-runtime";
2
+ import React from 'react';
3
+ import { TabList, Tab } from '.';
4
+ export const items = [
5
+ {
6
+ id: '1',
7
+ label: 'Items & Requests',
8
+ },
9
+ {
10
+ id: '2',
11
+ label: 'Courses',
12
+ },
13
+ {
14
+ id: '3',
15
+ label: 'Checkout',
16
+ },
17
+ {
18
+ id: '4',
19
+ label: 'History',
20
+ },
21
+ {
22
+ id: '5',
23
+ label: 'Preferences',
24
+ },
25
+ {
26
+ id: '6',
27
+ label: 'Reservations',
28
+ },
29
+ ];
30
+ const StateManager = ({ children }) => {
31
+ const [selected, setSelected] = React.useState('1');
32
+ return _jsx(_Fragment, { children: children({ selected, setSelected }) });
33
+ };
34
+ export const ExampleTabs = () => (_jsx(StateManager, { children: ({ selected, setSelected }) => (_jsx(TabList, { children: items.map((item) => (_jsx(Tab, Object.assign({ onClick: () => {
35
+ setSelected(item.id);
36
+ }, selected: selected === item.id }, { children: item.label }), item.id))) })) }));
@@ -0,0 +1,10 @@
1
+ import React from 'react';
2
+ import { StyledElementProps } from '../../../theme';
3
+ type TabListProps = StyledElementProps<HTMLDivElement>;
4
+ export declare const TabList: React.FC<TabListProps>;
5
+ type TabProps = StyledElementProps<HTMLButtonElement, {
6
+ selected?: boolean;
7
+ children: string;
8
+ }>;
9
+ export declare const Tab: React.FC<TabProps>;
10
+ export {};
@@ -0,0 +1,30 @@
1
+ var __rest = (this && this.__rest) || function (s, e) {
2
+ var t = {};
3
+ for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
4
+ t[p] = s[p];
5
+ if (s != null && typeof Object.getOwnPropertySymbols === "function")
6
+ for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
7
+ if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
8
+ t[p[i]] = s[p[i]];
9
+ }
10
+ return t;
11
+ };
12
+ import { jsx as _jsx } from "theme-ui/jsx-runtime";
13
+ import { TYPOGRAPHY_TYPE, getTypographyStyles } from '../../../theme/typography';
14
+ import { COLOR } from '../../../theme/colors';
15
+ import { useUniqueId } from '../../providers/uniqueIds';
16
+ export const TabList = (_a) => {
17
+ var { children, sx } = _a, props = __rest(_a, ["children", "sx"]);
18
+ return (_jsx("div", Object.assign({ role: "tablist", sx: Object.assign({ flexDirection: 'row' }, sx) }, props, { children: children })));
19
+ };
20
+ export const Tab = (_a) => {
21
+ var { selected, children } = _a, rest = __rest(_a, ["selected", "children"]);
22
+ const typographyStyles = getTypographyStyles(TYPOGRAPHY_TYPE.CONDENSED_TEXT_LARGE);
23
+ const labelId = useUniqueId('tab-label');
24
+ return (_jsx("button", Object.assign({ role: "tab", sx: Object.assign({ height: '3.25rem', boxSizing: 'border-box', px: 4, bg: COLOR.WHITE, color: selected ? COLOR.DARK_GRAY : COLOR.GRAY, border: 'none', borderBottom: selected ? 'solid 3px' : 'solid 1px', borderColor: selected ? COLOR.ND_BLUE_BRIGHT : COLOR.LIGHT_GRAY, cursor: 'pointer' }, typographyStyles), "aria-labelledby": labelId, "aria-selected": selected ? 'true' : 'false' }, rest, { children: _jsx("div", Object.assign({ id: labelId, sx: {
25
+ transform: selected ? 'scale(1.1)' : undefined,
26
+ ':hover': {
27
+ transform: selected ? 'scale(1.1)' : 'scale(1.05)',
28
+ },
29
+ } }, { children: children })) })));
30
+ };
@@ -0,0 +1,6 @@
1
+ import type { Meta, StoryObj } from '@storybook/react';
2
+ import { Table } from '.';
3
+ declare const meta: Meta<typeof Table>;
4
+ export default meta;
5
+ type Story = StoryObj<typeof Table>;
6
+ export declare const Default: Story;
@@ -0,0 +1,42 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { Table, TableColumn } from '.';
3
+ const meta = {
4
+ title: 'Elements/Table',
5
+ component: Table,
6
+ tags: ['autodocs'],
7
+ };
8
+ export default meta;
9
+ const data = [
10
+ {
11
+ name: 'Steve Rogers',
12
+ age: 100,
13
+ position: 'Ethics Officer',
14
+ },
15
+ {
16
+ name: 'Natasha Romanoff',
17
+ age: 35,
18
+ position: 'Opposition Researcher',
19
+ },
20
+ {
21
+ name: 'Thor',
22
+ age: 1500,
23
+ position: 'VP of Thunder',
24
+ },
25
+ {
26
+ name: 'Peter Parker',
27
+ age: 18,
28
+ position: 'Web Crawling Expert',
29
+ },
30
+ {
31
+ name: 'Kate Bishop',
32
+ age: 22,
33
+ position: 'Trust Fund Recipient',
34
+ },
35
+ ];
36
+ export const Default = {
37
+ render: () => (_jsxs(Table, Object.assign({ data: data, alternateRowColor: true }, { children: [_jsx(TableColumn, { header: "Name", dataKey: "name", sx: {
38
+ width: '160px',
39
+ } }), _jsx(TableColumn, Object.assign({ header: "Age", sx: {
40
+ width: '100px',
41
+ } }, { children: (row) => row.age })), _jsx(TableColumn, Object.assign({ header: "Occupation" }, { children: (row) => row.position }))] }))),
42
+ };
@@ -0,0 +1 @@
1
+ export declare const testExample: import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1,36 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { render } from '@testing-library/react';
3
+ import { Table, TableColumn } from '.';
4
+ const data = [
5
+ {
6
+ col1: 'Cell 1-1',
7
+ col2: 'Cell 1-2',
8
+ col3: 'Cell 1-3',
9
+ },
10
+ {
11
+ col1: 'Cell 2-1',
12
+ col2: 'Cell 2-2',
13
+ col3: 'Cell 2-3',
14
+ },
15
+ ];
16
+ export const testExample = (_jsxs(Table, Object.assign({ data: data }, { children: [_jsx(TableColumn, { header: "Column 1", dataKey: "col1" }), _jsx(TableColumn, Object.assign({ header: "Column 2" }, { children: (row) => row.col2 })), _jsx(TableColumn, { dataKey: "col3", header: _jsx("div", { children: "Column 3" }) })] })));
17
+ describe('Table', () => {
18
+ it('renders all headers and cells', () => {
19
+ const { getByText } = render(testExample);
20
+ const headers = ['Column 1', 'Column 2', 'Column 3'];
21
+ const cells = [
22
+ 'Cell 1-1',
23
+ 'Cell 1-2',
24
+ 'Cell 1-3',
25
+ 'Cell 2-1',
26
+ 'Cell 2-2',
27
+ 'Cell 2-3',
28
+ ];
29
+ headers.forEach((header) => {
30
+ expect(getByText(header)).toBeInTheDocument();
31
+ });
32
+ cells.forEach((cell) => {
33
+ expect(getByText(cell)).toBeInTheDocument();
34
+ });
35
+ });
36
+ });
@@ -0,0 +1,23 @@
1
+ /// <reference types="react" />
2
+ import { StyledElementProps, StylesProp } from '../../../theme';
3
+ type ColumnRenderFn<RowData> = (data: RowData) => React.ReactNode;
4
+ type ColumnProps<RowData extends object> = {
5
+ header: string | React.ReactNode;
6
+ dataKey?: keyof RowData;
7
+ headerStyles?: StylesProp;
8
+ align?: 'left' | 'center' | 'right';
9
+ alignHeader?: 'left' | 'center' | 'right';
10
+ children?: ColumnRenderFn<RowData>;
11
+ sx?: StylesProp;
12
+ };
13
+ type TableProps<RowData> = StyledElementProps<HTMLTableElement, {
14
+ data: RowData[];
15
+ children: JSX.Element[];
16
+ cellStyles?: StylesProp;
17
+ alternateRowColor?: boolean;
18
+ showRowDividers?: boolean;
19
+ showColumnDividers?: boolean;
20
+ }>;
21
+ export declare function TableColumn<RowData extends object>(props: ColumnProps<RowData>): null;
22
+ export declare function Table<RowData extends object>(props: TableProps<RowData>): import("react").JSX.Element;
23
+ export {};
@@ -0,0 +1,47 @@
1
+ import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "theme-ui/jsx-runtime";
2
+ import { useMemo } from 'react';
3
+ import { COLOR } from '../../../theme/colors';
4
+ import { useEnvironment } from '../../providers/env';
5
+ import { TYPOGRAPHY_TYPE, typographyStyleMap } from '../../../theme/typography';
6
+ const useColumnSpec = (children) => {
7
+ const columnList = JSON.stringify(children.map((child) => child.props.header));
8
+ return useMemo(() => {
9
+ return children.map((child) => child.props);
10
+ }, [columnList]);
11
+ };
12
+ export function TableColumn(props) {
13
+ const { flagInDevelopment } = useEnvironment();
14
+ flagInDevelopment('TableColumn should not be used outside of Table component');
15
+ console.log('We offer this log to you in reverence, oh compiler gods', props);
16
+ return null;
17
+ }
18
+ export function Table(props) {
19
+ const { role, data, alternateRowColor = true, cellStyles, sx, children, showRowDividers = true, showColumnDividers = false, } = props;
20
+ const cellTypographyStyles = typographyStyleMap[TYPOGRAPHY_TYPE.CONDENSED_TEXT_MEDIUM];
21
+ const headerTypographyStyles = typographyStyleMap[TYPOGRAPHY_TYPE.CONTROL_MEDIUM];
22
+ const columnSpec = useColumnSpec(children);
23
+ const getCellStyles = (params) => {
24
+ const { columnProps, rowIndex, columnIndex } = params;
25
+ const isLastColumn = columnIndex === columnSpec.length - 1;
26
+ const isLastRow = rowIndex === data.length - 1;
27
+ const cellAlign = columnProps.align || 'left';
28
+ const styles = Object.assign({ bg: alternateRowColor && rowIndex % 2 === 1
29
+ ? COLOR.EXTRA_EXTRA_LIGHT_GRAY
30
+ : COLOR.WHITE, p: 3, borderBottom: showRowDividers && !isLastRow ? '1px solid' : 'none', borderRight: showColumnDividers && !isLastColumn ? '1px solid' : 'none', borderColor: COLOR.LIGHT_GRAY, textAlign: cellAlign }, cellTypographyStyles);
31
+ return Object.assign(Object.assign(Object.assign({}, styles), cellStyles), columnProps.sx);
32
+ };
33
+ return (_jsxs("table", Object.assign({ role: role, sx: sx }, { children: [_jsx("thead", Object.assign({ role: "rowgroup" }, { children: _jsx("tr", { children: columnSpec.map((column, i) => {
34
+ const isLastColumn = i === columnSpec.length - 1;
35
+ return (_jsx("th", Object.assign({ role: "columnheader", sx: Object.assign(Object.assign({ textAlign: column.alignHeader || column.align || 'left', borderBottom: '1px solid', borderRight: showColumnDividers && !isLastColumn ? '1px solid' : 'none', borderColor: COLOR.LIGHT_GRAY, px: 3, pb: 1 }, headerTypographyStyles), column.headerStyles) }, { children: column.header }), i));
36
+ }) }) })), _jsx("tbody", Object.assign({ role: "rowgroup" }, { children: data.map((rowData, rowIndex) => {
37
+ return (_jsx("tr", Object.assign({ role: "row" }, { children: columnSpec.map((column, columnIndex) => {
38
+ const { children, dataKey } = column;
39
+ const cellStyles = getCellStyles({
40
+ columnProps: column,
41
+ rowIndex,
42
+ columnIndex,
43
+ });
44
+ return (_jsx("td", Object.assign({ sx: cellStyles }, { children: _jsxs(_Fragment, { children: [dataKey ? rowData[dataKey] : null, !dataKey && children && children(rowData)] }) }), columnIndex));
45
+ }) }), rowIndex));
46
+ }) }))] })));
47
+ }
@@ -1,4 +1,9 @@
1
- /// <reference types="react" />
1
+ import React from 'react';
2
2
  import { StyledElementProps } from '../../../theme';
3
3
  export type BoxProps = StyledElementProps<HTMLDivElement>;
4
- export declare const Box: React.FC<BoxProps>;
4
+ export declare const Box: React.ForwardRefExoticComponent<{
5
+ sx?: import("../../../theme").StylesProp | undefined;
6
+ children?: React.ReactNode;
7
+ } & Omit<React.HTMLAttributes<HTMLDivElement>, "children" | "onChange"> & object & {
8
+ htmlFor?: string | undefined;
9
+ } & React.RefAttributes<HTMLDivElement>>;
@@ -1,4 +1,3 @@
1
1
  import { jsx as _jsx } from "theme-ui/jsx-runtime";
2
- export const Box = (props) => {
3
- return _jsx("div", Object.assign({}, props));
4
- };
2
+ import React from 'react';
3
+ export const Box = React.forwardRef((props, ref) => (_jsx("div", Object.assign({}, props, { ref: ref }))));
@@ -1,6 +1,8 @@
1
- /// <reference types="react" />
2
- import { StyledElementProps } from '../../../theme';
1
+ import React from 'react';
3
2
  import { FlexHelperProps } from './Row';
4
- type ColumnProps = StyledElementProps<HTMLDivElement, FlexHelperProps>;
5
- export declare const Column: React.FC<ColumnProps>;
6
- export {};
3
+ export declare const Column: React.ForwardRefExoticComponent<{
4
+ sx?: import("../../../theme").StylesProp | undefined;
5
+ children?: React.ReactNode;
6
+ } & Omit<React.HTMLAttributes<HTMLDivElement>, "children" | "onChange"> & FlexHelperProps & {
7
+ htmlFor?: string | undefined;
8
+ } & React.RefAttributes<HTMLDivElement>>;
@@ -10,9 +10,10 @@ var __rest = (this && this.__rest) || function (s, e) {
10
10
  return t;
11
11
  };
12
12
  import { jsx as _jsx } from "theme-ui/jsx-runtime";
13
+ import React from 'react';
13
14
  import { convertFlexHelperProps } from './Row';
14
- export const Column = (_a) => {
15
+ export const Column = React.forwardRef((_a, ref) => {
15
16
  var { sx, children } = _a, rest = __rest(_a, ["sx", "children"]);
16
17
  const flexStyles = convertFlexHelperProps(rest);
17
- return (_jsx("div", Object.assign({}, rest, { sx: Object.assign(Object.assign(Object.assign({}, flexStyles), sx), { display: 'flex', flexDirection: 'column' }) }, { children: children })));
18
- };
18
+ return (_jsx("div", Object.assign({ ref: ref }, rest, { sx: Object.assign(Object.assign(Object.assign({}, flexStyles), sx), { display: 'flex', flexDirection: 'column' }) }, { children: children })));
19
+ });
@@ -1,6 +1,5 @@
1
- /// <reference types="react" />
2
1
  import { CSSProperties, ThemeUICSSProperties } from 'theme-ui';
3
- import { StyledElementProps } from '../../../theme';
2
+ import React from 'react';
4
3
  export declare const convertFlexHelperProps: (props: FlexHelperProps) => ThemeUICSSProperties;
5
4
  export type FlexHelperProps = {
6
5
  grow?: number;
@@ -11,8 +10,11 @@ export type FlexHelperProps = {
11
10
  justify?: CSSProperties['justifyContent'];
12
11
  centered?: boolean;
13
12
  };
14
- type RowProps = StyledElementProps<HTMLDivElement, FlexHelperProps & {
15
- breakpoint?: number;
16
- }>;
17
- export declare const Row: React.FC<RowProps>;
18
- export {};
13
+ export declare const Row: React.ForwardRefExoticComponent<{
14
+ sx?: import("../../../theme").StylesProp | undefined;
15
+ children?: React.ReactNode;
16
+ } & Omit<React.HTMLAttributes<HTMLDivElement>, "children" | "onChange"> & FlexHelperProps & {
17
+ breakpoint?: number | undefined;
18
+ } & {
19
+ htmlFor?: string | undefined;
20
+ } & React.RefAttributes<HTMLDivElement>>;
@@ -10,6 +10,7 @@ var __rest = (this && this.__rest) || function (s, e) {
10
10
  return t;
11
11
  };
12
12
  import { jsx as _jsx } from "theme-ui/jsx-runtime";
13
+ import React from 'react';
13
14
  export const convertFlexHelperProps = (props) => {
14
15
  const styleObject = {};
15
16
  if (props.grow) {
@@ -36,7 +37,7 @@ export const convertFlexHelperProps = (props) => {
36
37
  }
37
38
  return styleObject;
38
39
  };
39
- export const Row = (_a) => {
40
+ export const Row = React.forwardRef((_a, ref) => {
40
41
  var { sx, children, breakpoint: breakpointParam } = _a, rest = __rest(_a, ["sx", "children", "breakpoint"]);
41
42
  const flexStyles = convertFlexHelperProps(rest);
42
43
  let flexDirection = 'row';
@@ -47,5 +48,5 @@ export const Row = (_a) => {
47
48
  }
48
49
  flexDirection.push('row');
49
50
  }
50
- return (_jsx("div", Object.assign({}, rest, { sx: Object.assign(Object.assign(Object.assign({}, flexStyles), sx), { flexDirection, display: 'flex' }) }, { children: children })));
51
- };
51
+ return (_jsx("div", Object.assign({}, rest, { ref: ref, sx: Object.assign(Object.assign(Object.assign({}, flexStyles), sx), { flexDirection, display: 'flex' }) }, { children: children })));
52
+ });
@@ -2,8 +2,8 @@ import { jsx as _jsx } from "react/jsx-runtime";
2
2
  import React, { useEffect, useState } from 'react';
3
3
  import { useEnvironment } from './env';
4
4
  import { KEY_CODES, equals } from '../../utils/misc';
5
- import { useUniqueHtmlId } from '../../utils/hooks/useUniqueHtmlId';
6
5
  import { useCheckMidClick } from '../../utils/hooks/useCheckMidClick';
6
+ import { useUniqueId } from './uniqueIds';
7
7
  export var MENU_ACTION_TYPE;
8
8
  (function (MENU_ACTION_TYPE) {
9
9
  MENU_ACTION_TYPE["SUBMENU"] = "SUBMENU";
@@ -41,14 +41,14 @@ const inactiveStyles = {
41
41
  };
42
42
  export const MenuProvider = ({ menu, children, }) => {
43
43
  const { flagInDevelopment } = useEnvironment();
44
- const salt = useUniqueHtmlId();
44
+ const menuId = useUniqueId('hcl-menu');
45
45
  const { isMidClick, elementProps: checkMidclickProps } = useCheckMidClick();
46
46
  const [usingKeyboard, setUsingKeyboard] = useState(false);
47
47
  const closeOnBlurTimeout = React.useRef();
48
48
  const initialPath = React.useMemo(() => [menu.items[0].id], [menu]);
49
49
  const [activePath, setActivePath] = useState(initialPath);
50
50
  const [isOpen, setIsOpen] = useState(false);
51
- const getItemId = React.useCallback((path) => `menu-${salt}-item-${path.join('-')}`, [salt]);
51
+ const getItemId = React.useCallback((path) => `${menuId}-item-${path.join('-')}`, [menuId]);
52
52
  useEffect(() => {
53
53
  if (activePath && isOpen) {
54
54
  const activeChild = window.document.getElementById(getItemId(activePath));
@@ -0,0 +1,23 @@
1
+ /// <reference types="react" />
2
+ type SnackBarMessage = {
3
+ message: string;
4
+ content?: JSX.Element;
5
+ id?: string;
6
+ };
7
+ type SendMessageOptions = {
8
+ timeout?: number;
9
+ wipePrevious?: boolean;
10
+ };
11
+ type SnackBarMessageWithId = Omit<SnackBarMessage, 'id'> & {
12
+ id: string;
13
+ };
14
+ type AddMessage = (message: SnackBarMessage, options?: SendMessageOptions) => void;
15
+ type SnackBarContextType = {
16
+ addMessage: AddMessage;
17
+ removeMessage: (id: string) => void;
18
+ messages: SnackBarMessageWithId[];
19
+ previousMessageCount: number;
20
+ };
21
+ export declare const SnackBarProvider: React.FC<React.PropsWithChildren>;
22
+ export declare const useSnackBar: () => SnackBarContextType;
23
+ export {};
@@ -0,0 +1,53 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import { createContext, useCallback, useContext, useEffect, useRef, useState, } from 'react';
3
+ const DEFAULT_TIMEOUT = 10000;
4
+ const SnackBarContext = createContext({
5
+ addMessage: () => { },
6
+ removeMessage: () => { },
7
+ previousMessageCount: 0,
8
+ messages: [],
9
+ });
10
+ export const SnackBarProvider = ({ children, }) => {
11
+ const [messages, setMessages] = useState([]);
12
+ const removeMessageTimeouts = useRef([]);
13
+ const previousMessageCount = useRef(0);
14
+ const removeMessage = useCallback((id) => {
15
+ setMessages((messages) => {
16
+ previousMessageCount.current = messages.length;
17
+ return messages.filter((m) => m.id !== id);
18
+ });
19
+ }, []);
20
+ const addMessage = useCallback((message, options = {}) => {
21
+ const newRandomId = Math.random().toString(36).substring(7);
22
+ setMessages((messages) => {
23
+ previousMessageCount.current = options.wipePrevious
24
+ ? 0
25
+ : messages.length;
26
+ let newMessages = options.wipePrevious ? [] : [...messages];
27
+ newMessages = newMessages.filter((m) => m.id !== message.id);
28
+ newMessages.push(Object.assign(Object.assign({}, message), { id: message.id || newRandomId }));
29
+ if (newMessages.length > 3) {
30
+ newMessages.shift();
31
+ }
32
+ return newMessages;
33
+ });
34
+ const removeMessageTimeout = setTimeout(() => {
35
+ removeMessage(newRandomId);
36
+ }, options.timeout || DEFAULT_TIMEOUT);
37
+ removeMessageTimeouts.current.push(removeMessageTimeout);
38
+ }, [removeMessage]);
39
+ useEffect(() => {
40
+ return () => {
41
+ removeMessageTimeouts.current.forEach((timeout) => clearTimeout(timeout));
42
+ };
43
+ }, []);
44
+ return (_jsx(SnackBarContext.Provider, Object.assign({ value: {
45
+ messages,
46
+ removeMessage,
47
+ previousMessageCount: previousMessageCount.current,
48
+ addMessage,
49
+ } }, { children: children })));
50
+ };
51
+ export const useSnackBar = () => {
52
+ return useContext(SnackBarContext);
53
+ };
@@ -7,7 +7,9 @@ import { FontLoader } from '../../FontLoader';
7
7
  import { GlobalStyles } from '../../theme/GlobalStyles';
8
8
  import { DialogsProvider } from './dialogs';
9
9
  import { MediaSizeProvider } from './media';
10
+ import { SnackBarProvider } from './snackBar';
11
+ import { UniqueIdProvider } from './uniqueIds';
10
12
  export const UiProvider = ({ env, components, alertsConfig, children, includeTheme = true, loadFonts, loadGlobalStyles, }) => {
11
- const core = (_jsxs(EnvironmentProvider, Object.assign({ env: env }, { children: [_jsx(MediaSizeProvider, { children: _jsx(ComponentConfigProvider, Object.assign({ config: components || {} }, { children: _jsx(DialogsProvider, { children: _jsx(AlertsProvider, Object.assign({}, alertsConfig, { children: children })) }) })) }), loadGlobalStyles && _jsx(GlobalStyles, {}), loadFonts && _jsx(FontLoader, {})] })));
13
+ const core = (_jsxs(EnvironmentProvider, Object.assign({ env: env }, { children: [_jsx(MediaSizeProvider, { children: _jsx(ComponentConfigProvider, Object.assign({ config: components || {} }, { children: _jsx(UniqueIdProvider, { children: _jsx(SnackBarProvider, { children: _jsx(DialogsProvider, { children: _jsx(AlertsProvider, Object.assign({}, alertsConfig, { children: children })) }) }) }) })) }), loadGlobalStyles && _jsx(GlobalStyles, {}), loadFonts && _jsx(FontLoader, {})] })));
12
14
  return includeTheme ? _jsx(ThemeProvider, { children: core }) : core;
13
15
  };
@@ -0,0 +1,3 @@
1
+ import React from 'react';
2
+ export declare const UniqueIdProvider: React.FC<React.PropsWithChildren>;
3
+ export declare const useUniqueId: (prefix: string) => string;
@@ -0,0 +1,23 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import { createContext, useContext, useMemo, useRef } from 'react';
3
+ const UniqueIdContext = createContext({});
4
+ export const UniqueIdProvider = ({ children, }) => {
5
+ const countIndexRef = useRef({});
6
+ return (_jsx(UniqueIdContext.Provider, Object.assign({ value: countIndexRef.current }, { children: children })));
7
+ };
8
+ export const useUniqueId = (prefix) => {
9
+ const countIndex = useContext(UniqueIdContext);
10
+ return useMemo(() => {
11
+ var _a;
12
+ const idForPrefix = ((_a = countIndex[prefix]) === null || _a === void 0 ? void 0 : _a.count) || 1;
13
+ if (!countIndex[prefix]) {
14
+ countIndex[prefix] = {
15
+ count: 2,
16
+ };
17
+ }
18
+ else {
19
+ countIndex[prefix].count += 1;
20
+ }
21
+ return `${prefix}-${idForPrefix}`;
22
+ }, []);
23
+ };
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,26 @@
1
+ import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { render } from '@testing-library/react';
3
+ import { UniqueIdProvider, useUniqueId } from './uniqueIds';
4
+ const ExampleInner = () => {
5
+ const uniqueId1 = useUniqueId('test-1');
6
+ const uniqueId2 = useUniqueId('test-1');
7
+ const uniqueId3 = useUniqueId('test-2');
8
+ return (_jsxs(_Fragment, { children: [_jsx("div", { children: uniqueId1 }), _jsx("div", { children: uniqueId2 }), _jsx("div", { children: uniqueId3 })] }));
9
+ };
10
+ const ExampleOuter = () => {
11
+ return (_jsxs(UniqueIdProvider, { children: [_jsx(ExampleInner, {}), _jsx(ExampleInner, {}), _jsx(ExampleInner, {})] }));
12
+ };
13
+ describe('UniqueIdProvider', () => {
14
+ it('should generate unique ids', () => {
15
+ const { getByText } = render(_jsx(ExampleOuter, {}));
16
+ expect(getByText('test-1-1')).toBeInTheDocument();
17
+ expect(getByText('test-1-2')).toBeInTheDocument();
18
+ expect(getByText('test-2-1')).toBeInTheDocument();
19
+ expect(getByText('test-1-3')).toBeInTheDocument();
20
+ expect(getByText('test-1-4')).toBeInTheDocument();
21
+ expect(getByText('test-2-2')).toBeInTheDocument();
22
+ expect(getByText('test-1-5')).toBeInTheDocument();
23
+ expect(getByText('test-1-6')).toBeInTheDocument();
24
+ expect(getByText('test-2-3')).toBeInTheDocument();
25
+ });
26
+ });
package/dist/index.d.ts CHANGED
@@ -1,4 +1,5 @@
1
1
  export { theme, ThemeProvider, useTheme } from './theme';
2
+ export type { StylesProp } from './theme';
2
3
  export { COLOR } from './theme/colors';
3
4
  export { TYPOGRAPHY_TYPE, FONT, FONT_SIZE, FONT_WEIGHT, LINE_HEIGHT, } from './theme/typography';
4
5
  export { GlobalStyles } from './theme/GlobalStyles';
@@ -28,14 +29,21 @@ export { ReadMore } from './components/elements/text/ReadMore';
28
29
  export { Icon } from './components/elements/Icon';
29
30
  export { Spinner, SPINNER_SIZE } from './components/elements/Spinner';
30
31
  export { Pill, PILL_SIZE, PILL_TYPE } from './components/elements/Pill';
32
+ export { Table, TableColumn } from './components/elements/Table';
33
+ export { TabList, Tab } from './components/elements/TabList';
31
34
  export { Card, CARD_SIZE, CARD_LAYOUT } from './components/composites/Card';
35
+ export { SnackBar } from './components/composites/SnackBar';
32
36
  export { NavMenu } from './components/composites/NavMenu';
33
37
  export { EmptyState, EMPTY_STATE_SIZE, } from './components/composites/EmptyState';
34
38
  export { DropdownLinks } from './components/composites/DropdownLinks';
35
39
  export { Modal } from './components/composites/Modal';
40
+ export { DragDropList, DragHandle } from './components/composites/DragDropList';
41
+ export { Seo } from './components/composites/Seo';
36
42
  export { UiProvider } from './components/providers/ui';
37
43
  export { MenuProvider, useMenu } from './components/providers/menu';
44
+ export { SnackBarProvider, useSnackBar } from './components/providers/snackBar';
38
45
  export { useAlerts, AlertsProvider, ALERT_DOMAIN, } from './components/providers/alerts';
39
46
  export { MediaSizeProvider, useMediaQuery } from './components/providers/media';
40
47
  export { DialogsProvider, useDialog } from './components/providers/dialogs';
48
+ export { useUniqueId } from './components/providers/uniqueIds';
41
49
  export { useHover } from './utils/hooks/useHover';
package/dist/index.js CHANGED
@@ -28,14 +28,21 @@ export { ReadMore } from './components/elements/text/ReadMore';
28
28
  export { Icon } from './components/elements/Icon';
29
29
  export { Spinner, SPINNER_SIZE } from './components/elements/Spinner';
30
30
  export { Pill, PILL_SIZE, PILL_TYPE } from './components/elements/Pill';
31
+ export { Table, TableColumn } from './components/elements/Table';
32
+ export { TabList, Tab } from './components/elements/TabList';
31
33
  export { Card, CARD_SIZE, CARD_LAYOUT } from './components/composites/Card';
34
+ export { SnackBar } from './components/composites/SnackBar';
32
35
  export { NavMenu } from './components/composites/NavMenu';
33
36
  export { EmptyState, EMPTY_STATE_SIZE, } from './components/composites/EmptyState';
34
37
  export { DropdownLinks } from './components/composites/DropdownLinks';
35
38
  export { Modal } from './components/composites/Modal';
39
+ export { DragDropList, DragHandle } from './components/composites/DragDropList';
40
+ export { Seo } from './components/composites/Seo';
36
41
  export { UiProvider } from './components/providers/ui';
37
42
  export { MenuProvider, useMenu } from './components/providers/menu';
43
+ export { SnackBarProvider, useSnackBar } from './components/providers/snackBar';
38
44
  export { useAlerts, AlertsProvider, ALERT_DOMAIN, } from './components/providers/alerts';
39
45
  export { MediaSizeProvider, useMediaQuery } from './components/providers/media';
40
46
  export { DialogsProvider, useDialog } from './components/providers/dialogs';
47
+ export { useUniqueId } from './components/providers/uniqueIds';
41
48
  export { useHover } from './utils/hooks/useHover';
@@ -156,11 +156,10 @@ const globalStyles = css `
156
156
  @font-face {
157
157
  font-family: GPCMed;
158
158
  font-display: swap;
159
- src: url('https://static.nd.edu/fonts/gp-min/gpc-medium.woff2')
160
- format('woff2'),
161
- url('https://static.nd.edu/fonts/gp-min/gpc-medium.woff') format('woff'),
162
- url('https://static.nd.edu/fonts/gp-min/gpc-medium.ttf')
163
- format('truetype');
159
+ url('https://static.nd.edu/fonts/gp-min/gpc-medium.woff2') format('woff2'),
160
+ url('https://static.nd.edu/fonts/gp-min/gpc-medium.woff') format('woff'),
161
+ url('https://static.nd.edu/fonts/gp-min/gpc-medium.ttf')
162
+ format('truetype');
164
163
  }
165
164
  `;
166
165
  export const GlobalStyles = () => {
@@ -5,7 +5,7 @@ export declare enum BOX_SHADOW {
5
5
  }
6
6
  export declare enum Z_INDEX {
7
7
  NORMAL = 1,
8
- LABEL = 2,
9
- DROPDOWN = 3,
8
+ ELEVATED = 2,
9
+ DIALOG = 3,
10
10
  MODAL = 4
11
11
  }