@ndlib/component-library 0.0.47 → 0.0.50

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 (42) 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/Seo/SeoDataDisplay/index.d.ts +2 -0
  6. package/dist/components/composites/Seo/SeoDataDisplay/index.js +9 -0
  7. package/dist/components/composites/Seo/index.d.ts +11 -0
  8. package/dist/components/composites/Seo/index.js +16 -0
  9. package/dist/components/composites/Seo/seo.stories.d.ts +6 -0
  10. package/dist/components/composites/Seo/seo.stories.js +12 -0
  11. package/dist/components/composites/Seo/seo.test.d.ts +1 -0
  12. package/dist/components/composites/Seo/seo.test.js +56 -0
  13. package/dist/components/composites/Seo/useSiteMetadata.d.ts +9 -0
  14. package/dist/components/composites/Seo/useSiteMetadata.js +16 -0
  15. package/dist/components/elements/Alerts/index.js +0 -2
  16. package/dist/components/elements/Button/index.js +1 -1
  17. package/dist/components/elements/TabList/TabList.stories.d.ts +6 -0
  18. package/dist/components/elements/TabList/TabList.stories.js +12 -0
  19. package/dist/components/elements/TabList/TabList.test.d.ts +1 -0
  20. package/dist/components/elements/TabList/TabList.test.js +19 -0
  21. package/dist/components/elements/TabList/example.d.ts +7 -0
  22. package/dist/components/elements/TabList/example.js +36 -0
  23. package/dist/components/elements/TabList/index.d.ts +10 -0
  24. package/dist/components/elements/TabList/index.js +30 -0
  25. package/dist/components/elements/Table/Table.stories.d.ts +6 -0
  26. package/dist/components/elements/Table/Table.stories.js +42 -0
  27. package/dist/components/elements/Table/Table.test.d.ts +1 -0
  28. package/dist/components/elements/Table/Table.test.js +36 -0
  29. package/dist/components/elements/Table/index.d.ts +23 -0
  30. package/dist/components/elements/Table/index.js +47 -0
  31. package/dist/components/elements/layout/Box.d.ts +7 -2
  32. package/dist/components/elements/layout/Box.js +2 -3
  33. package/dist/components/elements/layout/Column.d.ts +7 -5
  34. package/dist/components/elements/layout/Column.js +4 -3
  35. package/dist/components/elements/layout/Row.d.ts +9 -7
  36. package/dist/components/elements/layout/Row.js +4 -3
  37. package/dist/components/providers/ui.d.ts +1 -0
  38. package/dist/components/providers/ui.js +3 -2
  39. package/dist/index.d.ts +4 -0
  40. package/dist/index.js +4 -0
  41. package/dist/theme/GlobalStyles.js +4 -5
  42. package/package.json +8 -3
@@ -0,0 +1,7 @@
1
+ import type { Meta, StoryObj } from '@storybook/react';
2
+ import { DragDropList } from './index';
3
+ declare const meta: Meta<typeof DragDropList>;
4
+ export default meta;
5
+ type Story = StoryObj<typeof DragDropList>;
6
+ export declare const Default: Story;
7
+ export declare const Disabled: Story;
@@ -0,0 +1,32 @@
1
+ import { Fragment as _Fragment, jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { DragDropList, DragHandle } from './index';
3
+ import React from 'react';
4
+ import { Paragraph } from '../../elements/text/Paragraph';
5
+ const meta = {
6
+ title: 'Composites/DragDropList',
7
+ component: DragDropList,
8
+ tags: ['autodocs'],
9
+ };
10
+ export default meta;
11
+ const _items = [
12
+ {
13
+ id: '1',
14
+ label: 'Foo',
15
+ accessibleLabel: 'Foo',
16
+ },
17
+ {
18
+ id: '2',
19
+ label: 'Bar',
20
+ accessibleLabel: 'Bar',
21
+ },
22
+ ];
23
+ const StateManager = ({ children }) => {
24
+ const [items, setItems] = React.useState(_items);
25
+ return _jsx(_Fragment, { children: children({ items, setItems }) });
26
+ };
27
+ export const Default = {
28
+ render: () => (_jsx(StateManager, { children: ({ items, setItems }) => (_jsx(DragDropList, Object.assign({ items: items, onReorder: ({ reorderedList }) => setItems(reorderedList) }, { children: (item) => (_jsxs(_Fragment, { children: [_jsx(DragHandle, {}), _jsx(Paragraph, Object.assign({ sx: { ml: 2 } }, { children: item.label }))] })) }))) })),
29
+ };
30
+ export const Disabled = {
31
+ render: () => (_jsx(DragDropList, Object.assign({ disabled: true, items: _items, onReorder: () => { } }, { children: (item) => (_jsxs(_Fragment, { children: [_jsx(DragHandle, {}), _jsx(Paragraph, Object.assign({ sx: { ml: 2 } }, { children: item.label }))] })) }))),
32
+ };
@@ -0,0 +1,23 @@
1
+ /// <reference types="react" />
2
+ import { DropResult } from 'react-beautiful-dnd';
3
+ import { StylesProp } from '../../../theme';
4
+ import { ButtonProps } from '../../elements/Button';
5
+ type DraggableItem = {
6
+ accessibleLabel: string;
7
+ };
8
+ type DragDropListProps<Item extends DraggableItem> = {
9
+ onReorder: (params: {
10
+ reorderedList: Item[];
11
+ dropEvent: DropResult;
12
+ }) => void;
13
+ items: Item[];
14
+ itemIdKey?: keyof Item;
15
+ wrapperStyles?: StylesProp;
16
+ itemStyles?: StylesProp;
17
+ dragItemsDirectly?: boolean;
18
+ disabled?: boolean;
19
+ children: (item: Item) => React.ReactNode;
20
+ };
21
+ export declare const DragHandle: React.FC<ButtonProps>;
22
+ export declare function DragDropList<Item extends DraggableItem>({ items, itemIdKey, wrapperStyles, itemStyles, children: renderChild, onReorder, disabled, dragItemsDirectly, }: DragDropListProps<Item>): import("react/jsx-runtime").JSX.Element;
23
+ export {};
@@ -0,0 +1,46 @@
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, Fragment as _Fragment } from "react/jsx-runtime";
13
+ import { DragDropContext, Droppable, Draggable, } from 'react-beautiful-dnd';
14
+ import DragIndicator from '@mui/icons-material/DragIndicator';
15
+ import { useUniqueHtmlId } from '../../../utils/hooks/useUniqueHtmlId';
16
+ import { BUTTON_TYPE, Button } from '../../elements/Button';
17
+ import { Column } from '../../elements/layout/Column';
18
+ import { Row } from '../../elements/layout/Row';
19
+ export const DragHandle = (_a) => {
20
+ var { sx } = _a, props = __rest(_a, ["sx"]);
21
+ return (_jsx(Button, Object.assign({ type: BUTTON_TYPE.TEXT, primaryIcon: DragIndicator, disableFocusStyles: true, sx: Object.assign({ cursor: 'inherit' }, sx) }, props)));
22
+ };
23
+ export function DragDropList({ items, itemIdKey = 'id', wrapperStyles, itemStyles, children: renderChild, onReorder, disabled, dragItemsDirectly = false, }) {
24
+ const id = useUniqueHtmlId('dnd-list');
25
+ return (_jsx(DragDropContext, Object.assign({ onDragStart: (start, provided) => {
26
+ const selectedItem = items.find((item) => String(item[itemIdKey]) === start.draggableId);
27
+ provided.announce(`Selected item: ${selectedItem === null || selectedItem === void 0 ? void 0 : selectedItem.accessibleLabel}`);
28
+ }, onDragEnd: (e) => {
29
+ if (e.destination &&
30
+ e.source &&
31
+ e.destination.index !== e.source.index) {
32
+ const reordered = Array.from(items);
33
+ const [removed] = reordered.splice(e.source.index, 1);
34
+ reordered.splice(e.destination.index, 0, removed);
35
+ onReorder({
36
+ reorderedList: reordered,
37
+ dropEvent: e,
38
+ });
39
+ }
40
+ } }, { children: _jsx(Droppable, Object.assign({ droppableId: id }, { children: (provided) => (_jsx(Column, Object.assign({}, provided.droppableProps, { sx: wrapperStyles, ref: provided.innerRef }, { children: _jsx(_Fragment, { children: items.map((item, index) => (_jsx(Draggable, Object.assign({ draggableId: String(item[itemIdKey]), isDragDisabled: disabled, index: index }, { children: (provided) => {
41
+ return (_jsx(Row, Object.assign({ sx: {
42
+ alignItems: 'center',
43
+ itemStyles,
44
+ }, ref: provided.innerRef }, provided.draggableProps, provided.dragHandleProps, { "aria-describedby": `item-${index}` }, (dragItemsDirectly ? provided.dragHandleProps : {}), { children: _jsx(Row, Object.assign({ sx: { mt: 1 }, id: `item-${index}` }, { children: renderChild(item) })) })));
45
+ } }), String(item[itemIdKey])))) }) }))) })) })));
46
+ }
@@ -0,0 +1,2 @@
1
+ export declare const SeoDataDisplay: () => import("react/jsx-runtime").JSX.Element;
2
+ export default SeoDataDisplay;
@@ -0,0 +1,9 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import ReactDOMServer from 'react-dom/server';
3
+ import pretty from 'pretty';
4
+ import { Seo } from '../index';
5
+ export const SeoDataDisplay = () => {
6
+ const seoHtml = ReactDOMServer.renderToString(_jsx(Seo, {}));
7
+ return (_jsx("code", { children: _jsx("pre", { children: pretty(seoHtml) }) }));
8
+ };
9
+ export default SeoDataDisplay;
@@ -0,0 +1,11 @@
1
+ import React from 'react';
2
+ interface SeoProps {
3
+ title?: string;
4
+ description?: string;
5
+ image?: string;
6
+ pathname?: string;
7
+ nofollow?: boolean;
8
+ noindex?: boolean;
9
+ }
10
+ export declare const Seo: React.FC<SeoProps>;
11
+ export default Seo;
@@ -0,0 +1,16 @@
1
+ import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { useSiteMetadata } from './useSiteMetadata';
3
+ export const Seo = ({ title, description, image, nofollow, noindex, }) => {
4
+ const { title: defaultTitle, description: defaultDescription, image: defaultImage, siteUrl, twitterUsername, nofollow: defaultNoindex, noindex: defaultNofollow, } = useSiteMetadata();
5
+ const seo = {
6
+ title: title || defaultTitle,
7
+ description: description || defaultDescription,
8
+ image: image ? siteUrl + image : siteUrl + defaultImage,
9
+ url: siteUrl + location.pathname || '',
10
+ twitterUsername,
11
+ nofollow: nofollow || defaultNofollow,
12
+ noindex: noindex || defaultNoindex,
13
+ };
14
+ return (_jsxs(_Fragment, { children: [seo.title ? _jsx("title", Object.assign({ "data-testid": "seo-title" }, { children: seo.title })) : null, seo.title ? (_jsx("meta", { "data-testid": "seo-twitter-title", name: "twitter:title", content: seo.title })) : null, seo.title ? (_jsx("meta", { "data-testid": "seo-og-title", property: "og:title", content: seo.title })) : null, seo.url ? (_jsx("meta", { "data-testid": "seo-twitter-url", name: "twitter:url", content: seo.url })) : null, seo.url ? (_jsx("meta", { "data-testid": "seo-og-url", property: "og:url", content: seo.url })) : null, seo.description ? (_jsx("meta", { "data-testid": "seo-twitter-description", name: "twitter:description", content: seo.description })) : null, seo.description ? (_jsx("meta", { "data-testid": "seo-og-description", property: "og:description", content: seo.description })) : null, seo.image ? (_jsx("meta", { "data-testid": "seo-twitter-image", name: "twitter:image", content: seo.image })) : null, seo.image ? (_jsx("meta", { "data-testid": "seo-og-image", name: "og:image", content: seo.image })) : null, seo.twitterUsername ? (_jsx("meta", { "data-testid": "seo-twitter-creator", name: "twitter:creator", content: seo.twitterUsername })) : null, seo.nofollow ? (_jsx("meta", { "data-testid": "seo-nofollow", name: "robots", content: "nofollow" })) : null, seo.noindex ? (_jsx("meta", { "data-testid": "seo-noindex", name: "robots", content: "noindex" })) : null, _jsx("meta", { name: "twitter:card", content: "summary_large_image" }), _jsx("meta", { name: "viewport", content: "width=device-width, initial-scale=1" })] }));
15
+ };
16
+ export default Seo;
@@ -0,0 +1,6 @@
1
+ import type { Meta, StoryObj } from '@storybook/react';
2
+ import Seo from './index';
3
+ declare const meta: Meta<typeof Seo>;
4
+ export default meta;
5
+ type Story = StoryObj<typeof Seo>;
6
+ export declare const Default: Story;
@@ -0,0 +1,12 @@
1
+ import { jsx as _jsx, Fragment as _Fragment } from "react/jsx-runtime";
2
+ import SeoDataDisplay from './SeoDataDisplay';
3
+ import Seo from './index';
4
+ const meta = {
5
+ title: 'Composites/Seo',
6
+ component: Seo,
7
+ tags: ['autodocs'],
8
+ };
9
+ export default meta;
10
+ export const Default = {
11
+ render: () => (_jsx(_Fragment, { children: _jsx(SeoDataDisplay, {}) })),
12
+ };
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,56 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import { render } from '../../../utils/test';
3
+ import { screen } from '@testing-library/dom';
4
+ import { Seo } from './index';
5
+ const title = 'Component Library';
6
+ const description = 'Component Library for the Hesburgh Libraries';
7
+ const image = '/image.png';
8
+ const nofollow = true;
9
+ const noindex = true;
10
+ describe('Seo', () => {
11
+ it('renders meta tag for title', () => {
12
+ render(_jsx(Seo, { title: title }));
13
+ const element = screen.getByTestId('seo-title');
14
+ expect(element).toContainHTML('Component Library');
15
+ });
16
+ it('renders meta tag for twitter title', () => {
17
+ render(_jsx(Seo, { title: title }));
18
+ const element = screen.getByTestId('seo-twitter-title');
19
+ expect(element).toContainHTML('Component Library');
20
+ });
21
+ it('renders meta tag for open graph title', () => {
22
+ render(_jsx(Seo, { title: title }));
23
+ const element = screen.getByTestId('seo-og-title');
24
+ expect(element).toContainHTML('Component Library');
25
+ });
26
+ it('renders meta tag for twitter description', () => {
27
+ render(_jsx(Seo, { description: description }));
28
+ const element = screen.getByTestId('seo-twitter-description');
29
+ expect(element).toContainHTML('Component Library for the Hesburgh Libraries');
30
+ });
31
+ it('renders meta tag for open graph description', () => {
32
+ render(_jsx(Seo, { description: description }));
33
+ const element = screen.getByTestId('seo-og-description');
34
+ expect(element).toContainHTML('Component Library for the Hesburgh Libraries');
35
+ });
36
+ it('renders meta tag for twitter image', () => {
37
+ render(_jsx(Seo, { image: image }));
38
+ const element = screen.getByTestId('seo-twitter-image');
39
+ expect(element).toContainHTML('https://www.library.nd.edu/image.png');
40
+ });
41
+ it('renders meta tag for og image', () => {
42
+ render(_jsx(Seo, { image: image }));
43
+ const element = screen.getByTestId('seo-og-image');
44
+ expect(element).toContainHTML('https://www.library.nd.edu/image.png');
45
+ });
46
+ it('renders meta tag for nofollow', () => {
47
+ render(_jsx(Seo, { nofollow: nofollow }));
48
+ const element = screen.getByTestId('seo-nofollow');
49
+ expect(element).toContainHTML('nofollow');
50
+ });
51
+ it('renders meta tag for noindex', () => {
52
+ render(_jsx(Seo, { noindex: noindex }));
53
+ const element = screen.getByTestId('seo-noindex');
54
+ expect(element).toContainHTML('noindex');
55
+ });
56
+ });
@@ -0,0 +1,9 @@
1
+ export declare const useSiteMetadata: () => {
2
+ title: string;
3
+ image: string;
4
+ description: string;
5
+ twitterUsername: string;
6
+ siteUrl: string;
7
+ nofollow: boolean;
8
+ noindex: boolean;
9
+ };
@@ -0,0 +1,16 @@
1
+ export const useSiteMetadata = () => {
2
+ const data = {
3
+ site: {
4
+ siteMetadata: {
5
+ title: 'Hesburgh Component Library',
6
+ image: '/images/fakeimage.png',
7
+ description: 'Component library for the Hesburgh Libraries',
8
+ twitterUsername: 'hlibraries',
9
+ siteUrl: 'https://www.library.nd.edu',
10
+ nofollow: false,
11
+ noindex: false,
12
+ },
13
+ },
14
+ };
15
+ return data.site.siteMetadata;
16
+ };
@@ -62,5 +62,3 @@ export const Alert = (_a) => {
62
62
  }[type];
63
63
  return (_jsxs(Row, Object.assign({ sx: Object.assign({}, style) }, rest, { children: [icon && _jsx(Icon, { icon: icon, sx: { mr: 4 }, size: FONT_SIZE.LG }), _jsx(Markdown, { content: description, sx: { mt: 1, flexGrow: 1 } }), _jsx(Button, Object.assign({ type: BUTTON_TYPE.TEXT, onClick: dismiss, sx: { ml: 4 } }, { children: "Dismiss" }))] })));
64
64
  };
65
- const myHeaders = new Headers();
66
- myHeaders.append('Content-Type', 'application/json');
@@ -72,7 +72,7 @@ export const Button = React.forwardRef((_a, ref) => {
72
72
  flagInDevelopment('Icon buttons should include aria-label prop for accessibility');
73
73
  }
74
74
  if (isIconButton) {
75
- hoverTransform = 'scale(1.15)';
75
+ hoverTransform = 'scale(1.05)';
76
76
  }
77
77
  if (type === BUTTON_TYPE.DEFAULT) {
78
78
  bg = color || COLOR.SECONDARY;
@@ -0,0 +1,6 @@
1
+ import type { Meta, StoryObj } from '@storybook/react';
2
+ import { TabList } from './index';
3
+ declare const meta: Meta<typeof TabList>;
4
+ export default meta;
5
+ type Story = StoryObj<typeof TabList>;
6
+ export declare const Default: Story;
@@ -0,0 +1,12 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import { TabList } from './index';
3
+ import { ExampleTabs } from './example';
4
+ const meta = {
5
+ title: 'Elements/TabList',
6
+ component: TabList,
7
+ tags: ['autodocs'],
8
+ };
9
+ export default meta;
10
+ export const Default = {
11
+ render: () => _jsx(ExampleTabs, {}),
12
+ };
@@ -0,0 +1 @@
1
+ export {};
@@ -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 { useUniqueHtmlId } from '../../../utils/hooks/useUniqueHtmlId';
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 = useUniqueHtmlId('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
+ });
@@ -9,6 +9,7 @@ export type UiConfig = {
9
9
  disableAlerts?: boolean;
10
10
  loadFonts?: boolean;
11
11
  loadGlobalStyles?: boolean;
12
+ includeTheme?: boolean;
12
13
  };
13
14
  type UiProviderProps = PropsWithChildren<UiConfig>;
14
15
  export declare const UiProvider: React.FC<UiProviderProps>;
@@ -7,6 +7,7 @@ import { FontLoader } from '../../FontLoader';
7
7
  import { GlobalStyles } from '../../theme/GlobalStyles';
8
8
  import { DialogsProvider } from './dialogs';
9
9
  import { MediaSizeProvider } from './media';
10
- export const UiProvider = ({ env, components, alertsConfig, children, loadFonts, loadGlobalStyles, }) => {
11
- return (_jsxs(EnvironmentProvider, Object.assign({ env: env }, { children: [_jsx(ThemeProvider, { 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, {})] })));
10
+ 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, {})] })));
12
+ return includeTheme ? _jsx(ThemeProvider, { children: core }) : core;
12
13
  };
package/dist/index.d.ts CHANGED
@@ -28,11 +28,15 @@ 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';
32
34
  export { NavMenu } from './components/composites/NavMenu';
33
35
  export { EmptyState, EMPTY_STATE_SIZE, } from './components/composites/EmptyState';
34
36
  export { DropdownLinks } from './components/composites/DropdownLinks';
35
37
  export { Modal } from './components/composites/Modal';
38
+ export { DragDropList, DragHandle } from './components/composites/DragDropList';
39
+ export { Seo } from './components/composites/Seo';
36
40
  export { UiProvider } from './components/providers/ui';
37
41
  export { MenuProvider, useMenu } from './components/providers/menu';
38
42
  export { useAlerts, AlertsProvider, ALERT_DOMAIN, } from './components/providers/alerts';
package/dist/index.js CHANGED
@@ -28,11 +28,15 @@ 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';
32
34
  export { NavMenu } from './components/composites/NavMenu';
33
35
  export { EmptyState, EMPTY_STATE_SIZE, } from './components/composites/EmptyState';
34
36
  export { DropdownLinks } from './components/composites/DropdownLinks';
35
37
  export { Modal } from './components/composites/Modal';
38
+ export { DragDropList, DragHandle } from './components/composites/DragDropList';
39
+ export { Seo } from './components/composites/Seo';
36
40
  export { UiProvider } from './components/providers/ui';
37
41
  export { MenuProvider, useMenu } from './components/providers/menu';
38
42
  export { useAlerts, AlertsProvider, ALERT_DOMAIN, } from './components/providers/alerts';
@@ -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 = () => {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ndlib/component-library",
3
- "version": "0.0.47",
3
+ "version": "0.0.50",
4
4
  "type": "module",
5
5
  "sideEffects": false,
6
6
  "files": [
@@ -44,6 +44,7 @@
44
44
  "@emotion/styled": "^11.11.0",
45
45
  "@mui/icons-material": "^5.11.16",
46
46
  "@mui/material": "^5.11.16",
47
+ "@types/pretty": "^2.0.1",
47
48
  "@storybook/addon-essentials": "^7.0.17",
48
49
  "@storybook/addon-interactions": "^7.0.18",
49
50
  "@storybook/addon-links": "^7.0.17",
@@ -54,6 +55,7 @@
54
55
  "@testing-library/react": "^14.0.0",
55
56
  "@testing-library/user-event": "^14.4.3",
56
57
  "@types/react": "^18.0.28",
58
+ "@types/react-beautiful-dnd": "^13.1.5",
57
59
  "@types/react-datepicker": "^4.15.0",
58
60
  "@types/react-dom": "^18.0.11",
59
61
  "@types/react-modal": "^3.16.0",
@@ -67,7 +69,8 @@
67
69
  "eslint-plugin-storybook": "^0.6.12",
68
70
  "husky": "^8.0.3",
69
71
  "jsdom": "^22.1.0",
70
- "prettier": "^2.8.8",
72
+ "prettier": "^3.0.3",
73
+ "pretty": "^2.0.0",
71
74
  "prop-types": "^15.8.1",
72
75
  "react": "^18.2.0",
73
76
  "react-dom": "^18.2.0",
@@ -79,10 +82,12 @@
79
82
  },
80
83
  "prettier": {
81
84
  "singleQuote": true,
82
- "semi": false
85
+ "semi": false,
86
+ "trailingComma": "all"
83
87
  },
84
88
  "dependencies": {
85
89
  "@floating-ui/react": "^0.24.5",
90
+ "react-beautiful-dnd": "^13.1.1",
86
91
  "react-datepicker": "^4.16.0",
87
92
  "react-markdown": "^8.0.7",
88
93
  "react-modal": "^3.16.1",