@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.
- package/dist/components/composites/DragDropList/DragDropList.stories.d.ts +7 -0
- package/dist/components/composites/DragDropList/DragDropList.stories.js +32 -0
- package/dist/components/composites/DragDropList/index.d.ts +23 -0
- package/dist/components/composites/DragDropList/index.js +46 -0
- package/dist/components/composites/DropdownLinks/index.js +3 -3
- package/dist/components/composites/Modal/Modal.stories.js +1 -1
- package/dist/components/composites/Seo/SeoDataDisplay/index.d.ts +2 -0
- package/dist/components/composites/Seo/SeoDataDisplay/index.js +9 -0
- package/dist/components/composites/Seo/index.d.ts +11 -0
- package/dist/components/composites/Seo/index.js +16 -0
- package/dist/components/composites/Seo/seo.stories.d.ts +6 -0
- package/dist/components/composites/Seo/seo.stories.js +12 -0
- package/dist/components/composites/Seo/seo.test.d.ts +1 -0
- package/dist/components/composites/Seo/seo.test.js +56 -0
- package/dist/components/composites/Seo/useSiteMetadata.d.ts +9 -0
- package/dist/components/composites/Seo/useSiteMetadata.js +16 -0
- package/dist/components/composites/SnackBar/SnackBar.stories.d.ts +8 -0
- package/dist/components/composites/SnackBar/SnackBar.stories.js +20 -0
- package/dist/components/composites/SnackBar/SnackBar.test.d.ts +1 -0
- package/dist/components/composites/SnackBar/SnackBar.test.js +75 -0
- package/dist/components/composites/SnackBar/examples.d.ts +3 -0
- package/dist/components/composites/SnackBar/examples.js +35 -0
- package/dist/components/composites/SnackBar/index.d.ts +1 -0
- package/dist/components/composites/SnackBar/index.js +45 -0
- package/dist/components/elements/Button/index.js +1 -1
- package/dist/components/elements/Fields/Select/index.js +6 -6
- package/dist/components/elements/Fields/TextInput/index.js +4 -4
- package/dist/components/elements/ListBox/index.d.ts +1 -1
- package/dist/components/elements/TabList/TabList.stories.d.ts +6 -0
- package/dist/components/elements/TabList/TabList.stories.js +12 -0
- package/dist/components/elements/TabList/TabList.test.d.ts +1 -0
- package/dist/components/elements/TabList/TabList.test.js +19 -0
- package/dist/components/elements/TabList/example.d.ts +7 -0
- package/dist/components/elements/TabList/example.js +36 -0
- package/dist/components/elements/TabList/index.d.ts +10 -0
- package/dist/components/elements/TabList/index.js +30 -0
- package/dist/components/elements/Table/Table.stories.d.ts +6 -0
- package/dist/components/elements/Table/Table.stories.js +42 -0
- package/dist/components/elements/Table/Table.test.d.ts +1 -0
- package/dist/components/elements/Table/Table.test.js +36 -0
- package/dist/components/elements/Table/index.d.ts +23 -0
- package/dist/components/elements/Table/index.js +47 -0
- package/dist/components/elements/layout/Box.d.ts +7 -2
- package/dist/components/elements/layout/Box.js +2 -3
- package/dist/components/elements/layout/Column.d.ts +7 -5
- package/dist/components/elements/layout/Column.js +4 -3
- package/dist/components/elements/layout/Row.d.ts +9 -7
- package/dist/components/elements/layout/Row.js +4 -3
- package/dist/components/providers/menu.js +3 -3
- package/dist/components/providers/snackBar.d.ts +23 -0
- package/dist/components/providers/snackBar.js +53 -0
- package/dist/components/providers/ui.js +3 -1
- package/dist/components/providers/uniqueIds.d.ts +3 -0
- package/dist/components/providers/uniqueIds.js +23 -0
- package/dist/components/providers/uniqueIds.test.d.ts +1 -0
- package/dist/components/providers/uniqueIds.test.js +26 -0
- package/dist/index.d.ts +8 -0
- package/dist/index.js +7 -0
- package/dist/theme/GlobalStyles.js +4 -5
- package/dist/theme/custom.d.ts +2 -2
- package/dist/theme/custom.js +2 -2
- package/package.json +8 -3
- package/dist/utils/hooks/useUniqueHtmlId.d.ts +0 -1
- package/dist/utils/hooks/useUniqueHtmlId.js +0 -7
|
@@ -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 { BUTTON_TYPE, Button } from '../../elements/Button';
|
|
16
|
+
import { Column } from '../../elements/layout/Column';
|
|
17
|
+
import { Row } from '../../elements/layout/Row';
|
|
18
|
+
import { useUniqueId } from '../../providers/uniqueIds';
|
|
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 = useUniqueId('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
|
+
}
|
|
@@ -13,16 +13,16 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
|
13
13
|
import { useCallback, useMemo, useState } from 'react';
|
|
14
14
|
import { autoPlacement, offset, size, useFloating } from '@floating-ui/react';
|
|
15
15
|
import { ListBox } from '../../elements/ListBox';
|
|
16
|
-
import { useUniqueHtmlId } from '../../../utils/hooks/useUniqueHtmlId';
|
|
17
16
|
import { Link } from '../../elements/Link';
|
|
18
17
|
import { Box } from '../../elements/layout/Box';
|
|
19
18
|
import { useComponentConfig } from '../../providers/componentConfig';
|
|
19
|
+
import { useUniqueId } from '../../providers/uniqueIds';
|
|
20
20
|
export const DropdownLinks = (_a) => {
|
|
21
21
|
var { children, options: optionsParam, renderOption: renderOptionParam, openNewTab, role = 'navigation' } = _a, rest = __rest(_a, ["children", "options", "renderOption", "openNewTab", "role"]);
|
|
22
22
|
const [isOpen, setIsOpen] = useState(false);
|
|
23
23
|
const [dropdownMinWidth, setDropdownMinWidth] = useState('0px');
|
|
24
|
-
const listboxId =
|
|
25
|
-
const anchorId =
|
|
24
|
+
const listboxId = useUniqueId('dropdown-links');
|
|
25
|
+
const anchorId = useUniqueId('dropdown-links-anchor');
|
|
26
26
|
const { navigate } = useComponentConfig().link;
|
|
27
27
|
const options = optionsParam.map((option) => (Object.assign(Object.assign({}, option), { onClick: () => {
|
|
28
28
|
if (option.onClick) {
|
|
@@ -14,7 +14,7 @@ const ModalExample = () => {
|
|
|
14
14
|
const modalId = 'modal-example';
|
|
15
15
|
const { open, close, state } = useDialog(modalId);
|
|
16
16
|
const theme = useTheme();
|
|
17
|
-
return (_jsxs(_Fragment, { children: [_jsx(Button, Object.assign({ onClick: open, sx: { position: 'relative', zIndex: theme.zIndex.
|
|
17
|
+
return (_jsxs(_Fragment, { children: [_jsx(Button, Object.assign({ onClick: open, sx: { position: 'relative', zIndex: theme.zIndex.DIALOG } }, { children: "Open Modal" })), _jsx(Modal, Object.assign({ isOpen: state.isOpen, heading: "Heading", close: close, actions: [
|
|
18
18
|
{
|
|
19
19
|
label: 'Secondary',
|
|
20
20
|
isPrimary: false,
|
|
@@ -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,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,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,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
|
+
};
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { SnackBar } from './';
|
|
2
|
+
import type { Meta, StoryObj } from '@storybook/react';
|
|
3
|
+
declare const meta: Meta<typeof SnackBar>;
|
|
4
|
+
export default meta;
|
|
5
|
+
type Story = StoryObj<typeof SnackBar>;
|
|
6
|
+
export declare const Default: Story;
|
|
7
|
+
export declare const ReplaceMessage: Story;
|
|
8
|
+
export declare const WipeMessages: Story;
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { SnackBar } from './';
|
|
3
|
+
import { BasicExample, ReplaceMessageExample, WipeMessagesExample, } from './examples';
|
|
4
|
+
const meta = {
|
|
5
|
+
title: 'Composites/SnackBar',
|
|
6
|
+
component: SnackBar,
|
|
7
|
+
};
|
|
8
|
+
export default meta;
|
|
9
|
+
export const Default = {
|
|
10
|
+
render: () => _jsx(BasicExample, {}),
|
|
11
|
+
args: {},
|
|
12
|
+
};
|
|
13
|
+
export const ReplaceMessage = {
|
|
14
|
+
render: () => _jsx(ReplaceMessageExample, {}),
|
|
15
|
+
args: {},
|
|
16
|
+
};
|
|
17
|
+
export const WipeMessages = {
|
|
18
|
+
render: () => _jsx(WipeMessagesExample, {}),
|
|
19
|
+
args: {},
|
|
20
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { act, fireEvent, waitFor } from '@testing-library/react';
|
|
3
|
+
import { vi } from 'vitest';
|
|
4
|
+
import { render } from '../../../utils/test';
|
|
5
|
+
import { BasicExample, ReplaceMessageExample, WipeMessagesExample, } from './examples';
|
|
6
|
+
vi.useFakeTimers();
|
|
7
|
+
describe('SnackBar', () => {
|
|
8
|
+
it('supports adding messages', () => {
|
|
9
|
+
const { getByText } = render(_jsx(BasicExample, {}));
|
|
10
|
+
expect(() => getByText('Message 1')).toThrow();
|
|
11
|
+
const addButton = getByText('Add Message');
|
|
12
|
+
act(() => {
|
|
13
|
+
fireEvent.click(addButton);
|
|
14
|
+
});
|
|
15
|
+
expect(getByText('Message 1')).toBeInTheDocument();
|
|
16
|
+
act(() => {
|
|
17
|
+
fireEvent.click(addButton);
|
|
18
|
+
});
|
|
19
|
+
expect(getByText('Message 1')).toBeInTheDocument();
|
|
20
|
+
expect(getByText('Message 2')).toBeInTheDocument();
|
|
21
|
+
act(() => {
|
|
22
|
+
vi.runAllTimers();
|
|
23
|
+
});
|
|
24
|
+
waitFor(() => {
|
|
25
|
+
expect(() => getByText('Message 1')).toThrow();
|
|
26
|
+
expect(() => getByText('Message 2')).toThrow();
|
|
27
|
+
});
|
|
28
|
+
});
|
|
29
|
+
it('supports replacing messages', () => {
|
|
30
|
+
const { getByText } = render(_jsx(ReplaceMessageExample, {}));
|
|
31
|
+
expect(() => getByText('Message 1')).toThrow();
|
|
32
|
+
const addButton = getByText('Add Message');
|
|
33
|
+
act(() => {
|
|
34
|
+
fireEvent.click(addButton);
|
|
35
|
+
});
|
|
36
|
+
expect(getByText('Message 1')).toBeInTheDocument();
|
|
37
|
+
act(() => {
|
|
38
|
+
fireEvent.click(addButton);
|
|
39
|
+
});
|
|
40
|
+
expect(() => getByText('Message 1')).toThrow();
|
|
41
|
+
expect(getByText('Message 2')).toBeInTheDocument();
|
|
42
|
+
act(() => {
|
|
43
|
+
vi.runAllTimers();
|
|
44
|
+
});
|
|
45
|
+
waitFor(() => {
|
|
46
|
+
expect(() => getByText('Message 2')).toThrow();
|
|
47
|
+
});
|
|
48
|
+
});
|
|
49
|
+
it('supports wiping messages', () => {
|
|
50
|
+
const { getByText } = render(_jsx(WipeMessagesExample, {}));
|
|
51
|
+
expect(() => getByText('Message 1')).toThrow();
|
|
52
|
+
const addButton = getByText('Add Message');
|
|
53
|
+
act(() => {
|
|
54
|
+
fireEvent.click(addButton);
|
|
55
|
+
});
|
|
56
|
+
act(() => {
|
|
57
|
+
fireEvent.click(addButton);
|
|
58
|
+
});
|
|
59
|
+
expect(getByText('Message 1')).toBeInTheDocument();
|
|
60
|
+
expect(getByText('Message 2')).toBeInTheDocument();
|
|
61
|
+
const wipeButton = getByText('Wipe and Add');
|
|
62
|
+
act(() => {
|
|
63
|
+
fireEvent.click(wipeButton);
|
|
64
|
+
});
|
|
65
|
+
expect(() => getByText('Message 1')).toThrow();
|
|
66
|
+
expect(() => getByText('Message 2')).toThrow();
|
|
67
|
+
expect(getByText('Message 3')).toBeInTheDocument();
|
|
68
|
+
act(() => {
|
|
69
|
+
vi.runAllTimers();
|
|
70
|
+
});
|
|
71
|
+
waitFor(() => {
|
|
72
|
+
expect(() => getByText('Message 3')).toThrow();
|
|
73
|
+
});
|
|
74
|
+
});
|
|
75
|
+
});
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { useState } from 'react';
|
|
3
|
+
import { useSnackBar } from '../../providers/snackBar';
|
|
4
|
+
import { Row } from '../../elements/layout/Row';
|
|
5
|
+
import { Button } from '../../elements/Button';
|
|
6
|
+
import { SnackBar } from '.';
|
|
7
|
+
export const BasicExample = () => {
|
|
8
|
+
const { addMessage } = useSnackBar();
|
|
9
|
+
const [messageCount, setMessageCount] = useState(1);
|
|
10
|
+
return (_jsxs(_Fragment, { children: [_jsx(Button, Object.assign({ onClick: () => {
|
|
11
|
+
setMessageCount(messageCount + 1);
|
|
12
|
+
addMessage({ message: `Message ${messageCount}` });
|
|
13
|
+
} }, { children: "Add Message" })), _jsx(SnackBar, {})] }));
|
|
14
|
+
};
|
|
15
|
+
export const ReplaceMessageExample = () => {
|
|
16
|
+
const { addMessage } = useSnackBar();
|
|
17
|
+
const [messageCount, setMessageCount] = useState(1);
|
|
18
|
+
return (_jsxs(_Fragment, { children: [_jsx(Button, Object.assign({ onClick: () => {
|
|
19
|
+
setMessageCount(messageCount + 1);
|
|
20
|
+
addMessage({ message: `Message ${messageCount}`, id: 'same-id' });
|
|
21
|
+
} }, { children: "Add Message" })), _jsx(SnackBar, {})] }));
|
|
22
|
+
};
|
|
23
|
+
export const WipeMessagesExample = () => {
|
|
24
|
+
const { addMessage } = useSnackBar();
|
|
25
|
+
const [messageCount, setMessageCount] = useState(1);
|
|
26
|
+
return (_jsxs(Row, { children: [_jsx(Button, Object.assign({ onClick: () => {
|
|
27
|
+
setMessageCount((count) => count + 1);
|
|
28
|
+
addMessage({ message: `Message ${messageCount}` });
|
|
29
|
+
}, sx: { mr: 1 } }, { children: "Add Message" })), _jsx(Button, Object.assign({ onClick: () => {
|
|
30
|
+
setMessageCount((count) => count + 1);
|
|
31
|
+
addMessage({ message: `Message ${messageCount}` }, {
|
|
32
|
+
wipePrevious: true,
|
|
33
|
+
});
|
|
34
|
+
} }, { children: "Wipe and Add" })), _jsx(SnackBar, {})] }));
|
|
35
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const SnackBar: () => import("react/jsx-runtime").JSX.Element;
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { keyframes } from '@emotion/react';
|
|
3
|
+
import { COLOR } from '../../../theme/colors';
|
|
4
|
+
import { TYPOGRAPHY_TYPE, getTypographyStyles } from '../../../theme/typography';
|
|
5
|
+
import { BUTTON_TYPE, Button } from '../../elements/Button';
|
|
6
|
+
import { Box } from '../../elements/layout/Box';
|
|
7
|
+
import { Column } from '../../elements/layout/Column';
|
|
8
|
+
import { Row } from '../../elements/layout/Row';
|
|
9
|
+
import { useSnackBar } from '../../providers/snackBar';
|
|
10
|
+
import CloseIcon from '@mui/icons-material/Close';
|
|
11
|
+
import { Z_INDEX } from '../../../theme/custom';
|
|
12
|
+
const getTransformForMessageCount = (messageCount) => messageCount ? `translateY(-${messageCount * 4 + 1}rem)` : '0rem';
|
|
13
|
+
const getAnimation = (messageCount, previousMessageCount) => {
|
|
14
|
+
return keyframes `
|
|
15
|
+
from {
|
|
16
|
+
transform: ${getTransformForMessageCount(previousMessageCount)};
|
|
17
|
+
}
|
|
18
|
+
to {
|
|
19
|
+
transform: ${getTransformForMessageCount(messageCount)};
|
|
20
|
+
}
|
|
21
|
+
`;
|
|
22
|
+
};
|
|
23
|
+
export const SnackBar = () => {
|
|
24
|
+
const { messages, removeMessage, previousMessageCount } = useSnackBar();
|
|
25
|
+
const typographyStyles = getTypographyStyles(TYPOGRAPHY_TYPE.CONDENSED_TEXT_MEDIUM);
|
|
26
|
+
const animation = getAnimation(messages.length, previousMessageCount);
|
|
27
|
+
const animationStyle = `${animation} 100ms linear 1 forwards`;
|
|
28
|
+
return (_jsx(Column, Object.assign({ sx: {
|
|
29
|
+
position: 'fixed',
|
|
30
|
+
left: 0,
|
|
31
|
+
top: '100%',
|
|
32
|
+
width: '100vw',
|
|
33
|
+
display: 'flex',
|
|
34
|
+
alignItems: 'center',
|
|
35
|
+
pb: 3,
|
|
36
|
+
animation: animationStyle,
|
|
37
|
+
zIndex: Z_INDEX.DIALOG,
|
|
38
|
+
} }, { children: messages.map((message) => (_jsxs(Row, Object.assign({ sx: Object.assign({ width: ['90vw', '500px'], height: '56px', borderRadius: '4px', p: 4, mt: '0.5rem', border: '1px solid', bg: COLOR.PRIMARY, color: COLOR.WHITE, justifyContent: 'space-between', alignItems: 'center' }, typographyStyles) }, { children: [_jsx(Box, Object.assign({ sx: {
|
|
39
|
+
overflow: 'hidden',
|
|
40
|
+
whiteSpace: 'nowrap',
|
|
41
|
+
textOverflow: 'ellipsis',
|
|
42
|
+
}, "aria-live": "polite" }, { children: message.message })), _jsx(Box, { children: _jsx(Button, { "aria-label": "Dismiss Notice", type: BUTTON_TYPE.TEXT, primaryIcon: CloseIcon, onClick: () => {
|
|
43
|
+
removeMessage(message.id);
|
|
44
|
+
}, textColor: COLOR.WHITE }) })] }), message.id))) })));
|
|
45
|
+
};
|
|
@@ -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.
|
|
75
|
+
hoverTransform = 'scale(1.05)';
|
|
76
76
|
}
|
|
77
77
|
if (type === BUTTON_TYPE.DEFAULT) {
|
|
78
78
|
bg = color || COLOR.SECONDARY;
|
|
@@ -8,11 +8,11 @@ import { INPUT_SIZE, labelOffsetMap, labelTypographyMap } from '../TextInput';
|
|
|
8
8
|
import { ListBox } from '../../ListBox';
|
|
9
9
|
import { BUTTON_SIZE, BUTTON_TYPE, Button } from '../../Button';
|
|
10
10
|
import { defaultRenderOptionLabel, getOptionId, } from '../option';
|
|
11
|
-
import { useUniqueHtmlId } from '../../../../utils/hooks/useUniqueHtmlId';
|
|
12
11
|
import { KEY_CODES, importedDefaultComponentShim } from '../../../../utils/misc';
|
|
13
12
|
import { COLOR } from '../../../../theme/colors';
|
|
14
13
|
import { Box } from '../../layout/Box';
|
|
15
14
|
import { Label } from '../../text/Label';
|
|
15
|
+
import { useUniqueId } from '../../../providers/uniqueIds';
|
|
16
16
|
const ArrowDropDownIcon = importedDefaultComponentShim(_ArrowDropDownIcon);
|
|
17
17
|
const typographyMap = {
|
|
18
18
|
[INPUT_SIZE.SM]: TYPOGRAPHY_TYPE.PARAGRAPH_SMALL,
|
|
@@ -32,8 +32,8 @@ const buttonSizeMap = {
|
|
|
32
32
|
const DEFAULT_WIDTH = '16rem';
|
|
33
33
|
export function Select({ size: sizeParam, placeholder, leftIcon, value, label, onSelectOption, options, renderOption, inverted, renderOptionLabel: renderOptionLabelParam, sx, }) {
|
|
34
34
|
const theme = useTheme();
|
|
35
|
-
const listboxId =
|
|
36
|
-
const inputId =
|
|
35
|
+
const listboxId = useUniqueId('select-list-box');
|
|
36
|
+
const inputId = useUniqueId('select-input');
|
|
37
37
|
const [isOpen, setIsOpen] = useState(false);
|
|
38
38
|
const [stagedOptionValue, setStagedOptionValue] = useState();
|
|
39
39
|
const currentOption = useMemo(() => {
|
|
@@ -132,7 +132,7 @@ export function Select({ size: sizeParam, placeholder, leftIcon, value, label, o
|
|
|
132
132
|
overflow: 'hidden',
|
|
133
133
|
minWidth: '0%',
|
|
134
134
|
borderColor: inverted ? COLOR.GRAY : COLOR.LIGHT_GRAY,
|
|
135
|
-
zIndex: theme.zIndex.
|
|
135
|
+
zIndex: theme.zIndex.ELEVATED,
|
|
136
136
|
} }, { children: _jsx("legend", Object.assign({ style: {
|
|
137
137
|
width: 'auto',
|
|
138
138
|
float: 'unset',
|
|
@@ -154,7 +154,7 @@ export function Select({ size: sizeParam, placeholder, leftIcon, value, label, o
|
|
|
154
154
|
position: 'absolute',
|
|
155
155
|
left: '0.5rem',
|
|
156
156
|
lineHeight: 1,
|
|
157
|
-
zIndex: theme.zIndex.
|
|
157
|
+
zIndex: theme.zIndex.ELEVATED,
|
|
158
158
|
color: inverted ? COLOR.EXTRA_LIGHT_GRAY : COLOR.PRIMARY,
|
|
159
159
|
px: 1,
|
|
160
160
|
top: labelOffsetMap[size],
|
|
@@ -171,7 +171,7 @@ export function Select({ size: sizeParam, placeholder, leftIcon, value, label, o
|
|
|
171
171
|
onSelectOption && onSelectOption(option.value);
|
|
172
172
|
close();
|
|
173
173
|
}, ref: refs.setFloating, renderOption: renderOption, sx: {
|
|
174
|
-
zIndex: theme.zIndex.
|
|
174
|
+
zIndex: theme.zIndex.DIALOG,
|
|
175
175
|
}, style: Object.assign(Object.assign({ minWidth: dropdownMinWidth }, floatingStyles), { boxShadow: inverted
|
|
176
176
|
? theme.boxShadow.INVERTED
|
|
177
177
|
: theme.boxShadow.NORMAL }) }))] })));
|
|
@@ -16,7 +16,7 @@ import { useTheme } from '../../../../theme';
|
|
|
16
16
|
import { Icon } from '../../Icon';
|
|
17
17
|
import { COLOR } from '../../../../theme/colors';
|
|
18
18
|
import { Label } from '../../text/Label';
|
|
19
|
-
import {
|
|
19
|
+
import { useUniqueId } from '../../../providers/uniqueIds';
|
|
20
20
|
export var INPUT_SIZE;
|
|
21
21
|
(function (INPUT_SIZE) {
|
|
22
22
|
INPUT_SIZE["SM"] = "sm";
|
|
@@ -50,7 +50,7 @@ const defaultHeight = {
|
|
|
50
50
|
};
|
|
51
51
|
export const TextInput = React.forwardRef((_a, ref) => {
|
|
52
52
|
var { value, label, onChange, onChangeRaw, onClick, inline, inverted, size: sizeParam, leftIcon, sx, disabled } = _a, rest = __rest(_a, ["value", "label", "onChange", "onChangeRaw", "onClick", "inline", "inverted", "size", "leftIcon", "sx", "disabled"]);
|
|
53
|
-
const id =
|
|
53
|
+
const id = useUniqueId('text-input');
|
|
54
54
|
const theme = useTheme();
|
|
55
55
|
const size = sizeParam || INPUT_SIZE.MD;
|
|
56
56
|
const display = inline === false ? 'flex' : 'inline-flex';
|
|
@@ -79,7 +79,7 @@ export const TextInput = React.forwardRef((_a, ref) => {
|
|
|
79
79
|
overflow: 'hidden',
|
|
80
80
|
minWidth: '0%',
|
|
81
81
|
borderColor: inverted ? COLOR.GRAY : COLOR.LIGHT_GRAY,
|
|
82
|
-
zIndex: theme.zIndex.
|
|
82
|
+
zIndex: theme.zIndex.ELEVATED,
|
|
83
83
|
}, "aria-ignore": true }, { children: _jsx("legend", Object.assign({ style: {
|
|
84
84
|
width: 'auto',
|
|
85
85
|
float: 'unset',
|
|
@@ -112,7 +112,7 @@ export const TextInput = React.forwardRef((_a, ref) => {
|
|
|
112
112
|
color: inverted ? COLOR.EXTRA_LIGHT_GRAY : COLOR.ND_PROVOST_BLUE,
|
|
113
113
|
left: '0.5rem',
|
|
114
114
|
lineHeight: 1,
|
|
115
|
-
zIndex: theme.zIndex.
|
|
115
|
+
zIndex: theme.zIndex.ELEVATED,
|
|
116
116
|
px: 1,
|
|
117
117
|
top: labelOffsetMap[size],
|
|
118
118
|
} }, { children: label })))] })));
|
|
@@ -13,7 +13,7 @@ type ListBoxProps<Value extends Key, Option extends BasicOption<Value>> = Styled
|
|
|
13
13
|
onBlur?: () => void;
|
|
14
14
|
}>;
|
|
15
15
|
export declare const ListBox: <Value extends React.Key = string, Option extends BasicOption<Value> = any>(props: {
|
|
16
|
-
sx?: import("
|
|
16
|
+
sx?: import("../../..").StylesProp | undefined;
|
|
17
17
|
children?: React.ReactNode;
|
|
18
18
|
} & Omit<React.HTMLAttributes<HTMLDivElement>, "children" | "onChange"> & {
|
|
19
19
|
options: Option[];
|
|
@@ -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 {};
|