@squiz/resource-browser 1.32.1-alpha.12
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/.storybook/main.ts +23 -0
- package/.storybook/preview-head.html +15 -0
- package/.storybook/preview.ts +16 -0
- package/build.js +21 -0
- package/jest.config.ts +18 -0
- package/lib/Icons/Generics/ArrowDown.d.ts +15 -0
- package/lib/Icons/Generics/ArrowDown.js +23 -0
- package/lib/Icons/Generics/ArrowRight.d.ts +15 -0
- package/lib/Icons/Generics/ArrowRight.js +23 -0
- package/lib/Icons/Generics/Close.d.ts +15 -0
- package/lib/Icons/Generics/Close.js +23 -0
- package/lib/Icons/Generics/GenericIconMap.d.ts +10 -0
- package/lib/Icons/Generics/GenericIconMap.js +14 -0
- package/lib/Icons/Generics/ResourceSelect.d.ts +15 -0
- package/lib/Icons/Generics/ResourceSelect.js +28 -0
- package/lib/Icons/Generics/Root.d.ts +15 -0
- package/lib/Icons/Generics/Root.js +23 -0
- package/lib/Icons/Generics/Selected.d.ts +15 -0
- package/lib/Icons/Generics/Selected.js +23 -0
- package/lib/Icons/Generics/index.d.ts +6 -0
- package/lib/Icons/Generics/index.js +19 -0
- package/lib/Icons/Icon.d.ts +47 -0
- package/lib/Icons/Icon.js +44 -0
- package/lib/Icons/MatrixResources/Audio.d.ts +15 -0
- package/lib/Icons/MatrixResources/Audio.js +28 -0
- package/lib/Icons/MatrixResources/Excel.d.ts +15 -0
- package/lib/Icons/MatrixResources/Excel.js +27 -0
- package/lib/Icons/MatrixResources/Folder.d.ts +15 -0
- package/lib/Icons/MatrixResources/Folder.js +24 -0
- package/lib/Icons/MatrixResources/GenericFile.d.ts +15 -0
- package/lib/Icons/MatrixResources/GenericFile.js +28 -0
- package/lib/Icons/MatrixResources/Image.d.ts +15 -0
- package/lib/Icons/MatrixResources/Image.js +26 -0
- package/lib/Icons/MatrixResources/MatrixResourceMap.d.ts +15 -0
- package/lib/Icons/MatrixResources/MatrixResourceMap.js +19 -0
- package/lib/Icons/MatrixResources/Page.d.ts +15 -0
- package/lib/Icons/MatrixResources/Page.js +30 -0
- package/lib/Icons/MatrixResources/Pdf.d.ts +15 -0
- package/lib/Icons/MatrixResources/Pdf.js +31 -0
- package/lib/Icons/MatrixResources/Powerpoint.d.ts +15 -0
- package/lib/Icons/MatrixResources/Powerpoint.js +28 -0
- package/lib/Icons/MatrixResources/Site.d.ts +15 -0
- package/lib/Icons/MatrixResources/Site.js +30 -0
- package/lib/Icons/MatrixResources/Video.d.ts +15 -0
- package/lib/Icons/MatrixResources/Video.js +24 -0
- package/lib/Icons/MatrixResources/Word.d.ts +17 -0
- package/lib/Icons/MatrixResources/Word.js +28 -0
- package/lib/Icons/MatrixResources/index.d.ts +11 -0
- package/lib/Icons/MatrixResources/index.js +29 -0
- package/lib/Modal/Modal.d.ts +11 -0
- package/lib/Modal/Modal.js +46 -0
- package/lib/Modal/ModalOpeningButton.d.ts +10 -0
- package/lib/Modal/ModalOpeningButton.js +13 -0
- package/lib/Modal/ModalTrigger.d.ts +9 -0
- package/lib/Modal/ModalTrigger.js +24 -0
- package/lib/PreviewPanel/PreviewModal.d.ts +11 -0
- package/lib/PreviewPanel/PreviewModal.js +81 -0
- package/lib/PreviewPanel/PreviewPanel.d.ts +16 -0
- package/lib/PreviewPanel/PreviewPanel.js +87 -0
- package/lib/PreviewPanel/details/MatrixResource.d.ts +12 -0
- package/lib/PreviewPanel/details/MatrixResource.js +41 -0
- package/lib/ResourceBreadcrumb/ResourceBreadcrumb.d.ts +9 -0
- package/lib/ResourceBreadcrumb/ResourceBreadcrumb.js +20 -0
- package/lib/ResourceItem/ResourceItem.d.ts +19 -0
- package/lib/ResourceItem/ResourceItem.js +26 -0
- package/lib/ResourceList/ResourceList.d.ts +14 -0
- package/lib/ResourceList/ResourceList.js +51 -0
- package/lib/ResourcePickerContainer/ResourcePickerContainer.d.ts +15 -0
- package/lib/ResourcePickerContainer/ResourcePickerContainer.js +145 -0
- package/lib/Skeleton/List/SkeletonList.d.ts +6 -0
- package/lib/Skeleton/List/SkeletonList.js +13 -0
- package/lib/Skeleton/ListItem/SkeletonListItem.d.ts +2 -0
- package/lib/Skeleton/ListItem/SkeletonListItem.js +15 -0
- package/lib/SourceDropdown/SourceDropdown.d.ts +9 -0
- package/lib/SourceDropdown/SourceDropdown.js +106 -0
- package/lib/SourceList/SourceList.d.ts +14 -0
- package/lib/SourceList/SourceList.js +58 -0
- package/lib/Spinner/Spinner.d.ts +8 -0
- package/lib/Spinner/Spinner.js +12 -0
- package/lib/index.css +968 -0
- package/lib/index.d.ts +37 -0
- package/lib/index.js +15 -0
- package/lib/uuid.d.ts +1 -0
- package/lib/uuid.js +8 -0
- package/package.json +74 -0
- package/postcss.config.js +11 -0
- package/src/Icons/Generics/ArrowDown.tsx +27 -0
- package/src/Icons/Generics/ArrowRight.tsx +27 -0
- package/src/Icons/Generics/Close.tsx +26 -0
- package/src/Icons/Generics/GenericIconMap.ts +14 -0
- package/src/Icons/Generics/ResourceSelect.tsx +40 -0
- package/src/Icons/Generics/Root.tsx +24 -0
- package/src/Icons/Generics/Selected.tsx +27 -0
- package/src/Icons/Generics/index.tsx +7 -0
- package/src/Icons/Icon.spec.tsx +62 -0
- package/src/Icons/Icon.stories.tsx +105 -0
- package/src/Icons/Icon.tsx +61 -0
- package/src/Icons/MatrixResources/Audio.tsx +30 -0
- package/src/Icons/MatrixResources/Excel.tsx +29 -0
- package/src/Icons/MatrixResources/Folder.tsx +29 -0
- package/src/Icons/MatrixResources/GenericFile.tsx +34 -0
- package/src/Icons/MatrixResources/Image.tsx +36 -0
- package/src/Icons/MatrixResources/MatrixResourceMap.ts +19 -0
- package/src/Icons/MatrixResources/Page.tsx +33 -0
- package/src/Icons/MatrixResources/Pdf.tsx +34 -0
- package/src/Icons/MatrixResources/Powerpoint.tsx +34 -0
- package/src/Icons/MatrixResources/Site.tsx +37 -0
- package/src/Icons/MatrixResources/Video.tsx +27 -0
- package/src/Icons/MatrixResources/Word.tsx +30 -0
- package/src/Icons/MatrixResources/index.tsx +12 -0
- package/src/Modal/Modal.spec.tsx +244 -0
- package/src/Modal/Modal.tsx +58 -0
- package/src/Modal/ModalContainer.stories.tsx +33 -0
- package/src/Modal/ModalOpeningButton.tsx +20 -0
- package/src/Modal/ModalTrigger.tsx +45 -0
- package/src/PreviewPanel/PreviewModal.spec.tsx +164 -0
- package/src/PreviewPanel/PreviewModal.tsx +92 -0
- package/src/PreviewPanel/PreviewPanel.spec.tsx +197 -0
- package/src/PreviewPanel/PreviewPanel.stories.tsx +61 -0
- package/src/PreviewPanel/PreviewPanel.tsx +123 -0
- package/src/PreviewPanel/details/MatrixResource.tsx +59 -0
- package/src/ResourceBreadcrumb/ResourceBreadcrumb.spec.tsx +76 -0
- package/src/ResourceBreadcrumb/ResourceBreadcrumb.stories.tsx +24 -0
- package/src/ResourceBreadcrumb/ResourceBreadcrumb.tsx +39 -0
- package/src/ResourceBreadcrumb/sample-hierarchy.json +23 -0
- package/src/ResourceItem/ResourceItem.spec.tsx +69 -0
- package/src/ResourceItem/ResourceItem.tsx +82 -0
- package/src/ResourceList/ResourceList.spec.tsx +196 -0
- package/src/ResourceList/ResourceList.stories.tsx +40 -0
- package/src/ResourceList/ResourceList.tsx +74 -0
- package/src/ResourceList/sample-resources.json +75 -0
- package/src/ResourcePickerContainer/ResourcePickerContainer.spec.tsx +706 -0
- package/src/ResourcePickerContainer/ResourcePickerContainer.stories.tsx +56 -0
- package/src/ResourcePickerContainer/ResourcePickerContainer.tsx +224 -0
- package/src/Skeleton/List/SkeletonList.spec.tsx +18 -0
- package/src/Skeleton/List/SkeletonList.stories.tsx +15 -0
- package/src/Skeleton/List/SkeletonList.tsx +16 -0
- package/src/Skeleton/ListItem/SkeletonListItem.stories.tsx +15 -0
- package/src/Skeleton/ListItem/SkeletonListItem.tsx +14 -0
- package/src/SourceDropdown/SourceDropdown.spec.tsx +263 -0
- package/src/SourceDropdown/SourceDropdown.stories.tsx +36 -0
- package/src/SourceDropdown/SourceDropdown.tsx +175 -0
- package/src/SourceDropdown/sample-sources.json +110 -0
- package/src/SourceList/SourceList.spec.tsx +224 -0
- package/src/SourceList/SourceList.stories.tsx +40 -0
- package/src/SourceList/SourceList.tsx +93 -0
- package/src/SourceList/sample-sources.json +110 -0
- package/src/Spinner/Spinner.spec.tsx +18 -0
- package/src/Spinner/Spinner.stories.tsx +26 -0
- package/src/Spinner/Spinner.tsx +18 -0
- package/src/Spinner/_spinner.scss +11 -0
- package/src/__mocks__/JestHelpers.ts +65 -0
- package/src/__mocks__/jestHelpers.spec.ts +38 -0
- package/src/__mocks__/styleMock.ts +1 -0
- package/src/index.scss +7 -0
- package/src/index.stories.tsx +70 -0
- package/src/index.tsx +71 -0
- package/src/uuid.ts +7 -0
- package/tailwind.config.cjs +84 -0
- package/tsconfig.json +22 -0
@@ -0,0 +1,29 @@
|
|
1
|
+
import React from 'react';
|
2
|
+
|
3
|
+
/**
|
4
|
+
* Renders the Folder icon
|
5
|
+
* @param {React.SVGProps<SVGSVGElement>} props - The props for the Folder component
|
6
|
+
* @returns {JSX.Element} - The Folder component
|
7
|
+
* @example
|
8
|
+
* <Folder />
|
9
|
+
* @example
|
10
|
+
* <Folder height={24} width={24} />
|
11
|
+
* @example
|
12
|
+
* <Folder className="custom-class" />
|
13
|
+
*/
|
14
|
+
export default function Folder({ isDecorative, ...props }: { isDecorative: boolean } & React.SVGProps<SVGSVGElement>) {
|
15
|
+
return (
|
16
|
+
<svg fill="none" height="24" viewBox="0 0 24 24" width="24" xmlns="http://www.w3.org/2000/svg" {...props}>
|
17
|
+
<path
|
18
|
+
d="m1 5c0-1.10457.89543-2 2-2h8.1177c.6752 0 1.3049.34077 1.6743.9061l2.208 3.37961-14 3.71429z"
|
19
|
+
fill="#efb324"
|
20
|
+
/>
|
21
|
+
<path
|
22
|
+
d="m3 6.5c-.82843 0-1.5.67157-1.5 1.5v11.5c0 .5523.44771 1 1 1h18.5c.8284 0 1.5-.6716 1.5-1.5v-11c0-.82843-.6716-1.5-1.5-1.5h-7.5106-2.8369z"
|
23
|
+
fill="#fbefd2"
|
24
|
+
stroke="#f5d584"
|
25
|
+
/>
|
26
|
+
{!isDecorative && <title>folder icon</title>}
|
27
|
+
</svg>
|
28
|
+
);
|
29
|
+
}
|
@@ -0,0 +1,34 @@
|
|
1
|
+
import React from 'react';
|
2
|
+
|
3
|
+
/**
|
4
|
+
* Renders the GenericFile icon
|
5
|
+
* @param {React.SVGProps<SVGSVGElement>} props - The props for the GenericFile component
|
6
|
+
* @returns {JSX.Element} - The GenericFile component
|
7
|
+
* @example
|
8
|
+
* <GenericFile />
|
9
|
+
* @example
|
10
|
+
* <GenericFile height={24} width={24} />
|
11
|
+
* @example
|
12
|
+
* <GenericFile className="custom-class" />
|
13
|
+
*/
|
14
|
+
export default function GenericFile({
|
15
|
+
isDecorative,
|
16
|
+
...props
|
17
|
+
}: { isDecorative: boolean } & React.SVGProps<SVGSVGElement>) {
|
18
|
+
return (
|
19
|
+
<svg fill="none" height="24" viewBox="0 0 24 24" width="24" xmlns="http://www.w3.org/2000/svg" {...props}>
|
20
|
+
<path
|
21
|
+
d="m15.9393 3.23223-.3515.35154.3515-.35154c-.4688-.46884-1.1047-.73223-1.7677-.73223h-8.1716c-.82843 0-1.5.67157-1.5 1.5v16c0 .8284.67157 1.5 1.5 1.5h12c.8284 0 1.5-.6716 1.5-1.5v-12.17157c0-.66304-.2634-1.29893-.7322-1.76777z"
|
22
|
+
fill="#fff"
|
23
|
+
stroke="#74b1e6"
|
24
|
+
/>
|
25
|
+
<path d="m14.5 3v3.5c0 .55228.4477 1 1 1h3.5" stroke="#74b1e6" />
|
26
|
+
<path d="m14.5 7.5v-5l5 5z" fill="#cce2f6" />
|
27
|
+
<g stroke="#74b1e6">
|
28
|
+
<path d="m15.9393 3.23223-.3515.35154.3515-.35154c-.4688-.46884-1.1047-.73223-1.7677-.73223h-8.1716c-.82843 0-1.5.67157-1.5 1.5v16c0 .8284.67157 1.5 1.5 1.5h12c.8284 0 1.5-.6716 1.5-1.5v-12.17157c0-.66304-.2634-1.29893-.7322-1.76777z" />
|
29
|
+
<path d="m14.5 3v3.5c0 .55228.4477 1 1 1h3.5" />
|
30
|
+
</g>
|
31
|
+
{!isDecorative && <title>generic file icon</title>}
|
32
|
+
</svg>
|
33
|
+
);
|
34
|
+
}
|
@@ -0,0 +1,36 @@
|
|
1
|
+
import React from 'react';
|
2
|
+
|
3
|
+
/**
|
4
|
+
* Renders the Image icon
|
5
|
+
* @param {React.SVGProps<SVGSVGElement>} props - The props for the Image component
|
6
|
+
* @returns {JSX.Element} - The Image component
|
7
|
+
* @example
|
8
|
+
* <Image />
|
9
|
+
* @example
|
10
|
+
* <Image height={24} width={24} />
|
11
|
+
* @example
|
12
|
+
* <Image className="custom-class" />
|
13
|
+
*/
|
14
|
+
export default function Image({ isDecorative, ...props }: { isDecorative: boolean } & React.SVGProps<SVGSVGElement>) {
|
15
|
+
return (
|
16
|
+
<svg fill="none" height="24" viewBox="0 0 24 24" width="24" xmlns="http://www.w3.org/2000/svg" {...props}>
|
17
|
+
<path
|
18
|
+
d="m21 17.5h.5v-.5-13c0-.82843-.6716-1.5-1.5-1.5h-16c-.82843 0-1.5.67157-1.5 1.5v13 .5h.5z"
|
19
|
+
fill="#cce2f6"
|
20
|
+
stroke="#74b1e6"
|
21
|
+
/>
|
22
|
+
<circle cx="15.5" cy="8.5" fill="#fbefd2" r="3" stroke="#f0c14f" />
|
23
|
+
<path
|
24
|
+
d="m21.3749 16.0025.1251.1418v.189 3.6667c0 .8284-.6716 1.5-1.5 1.5h-8.5-1.1506l.7851-.8412 6.2481-6.6944c.6044-.6476 1.6353-.6331 2.2214.031z"
|
25
|
+
fill="#cee9d8"
|
26
|
+
stroke="#79c292"
|
27
|
+
/>
|
28
|
+
<path
|
29
|
+
d="m2.62777 13.6262-.12777.1424v.1914 6.04c0 .8284.67157 1.5 1.5 1.5h13 1.0974l-.7201-.8281-9.25697-10.6455c-.59189-.68068-1.64634-.68877-2.2486-.0173z"
|
30
|
+
fill="#79c292"
|
31
|
+
stroke="#098934"
|
32
|
+
/>
|
33
|
+
{!isDecorative && <title>image icon</title>}
|
34
|
+
</svg>
|
35
|
+
);
|
36
|
+
}
|
@@ -0,0 +1,19 @@
|
|
1
|
+
import { Audio, Excel, Folder, GenericFile, Image, Page, Pdf, Powerpoint, Site, Video, Word } from '.';
|
2
|
+
|
3
|
+
// Define our map of matrix types to icons
|
4
|
+
const MatrixResourceMap = {
|
5
|
+
audio: Audio,
|
6
|
+
excel: Excel,
|
7
|
+
folder: Folder,
|
8
|
+
generic_file: GenericFile,
|
9
|
+
image: Image,
|
10
|
+
page_standard: Page,
|
11
|
+
pdf: Pdf,
|
12
|
+
powerpoint: Powerpoint,
|
13
|
+
site: Site,
|
14
|
+
video: Video,
|
15
|
+
word: Word,
|
16
|
+
};
|
17
|
+
|
18
|
+
// Export our map
|
19
|
+
export default MatrixResourceMap;
|
@@ -0,0 +1,33 @@
|
|
1
|
+
import React from 'react';
|
2
|
+
|
3
|
+
/**
|
4
|
+
* Renders the Page icon
|
5
|
+
* @param {React.SVGProps<SVGSVGElement>} props - The props for the Page component
|
6
|
+
* @returns {JSX.Element} - The Page component
|
7
|
+
* @example
|
8
|
+
* <Page />
|
9
|
+
* @example
|
10
|
+
* <Page height={24} width={24} />
|
11
|
+
* @example
|
12
|
+
* <Page className="custom-class" />
|
13
|
+
*/
|
14
|
+
export default function Page({ isDecorative, ...props }: { isDecorative: boolean } & React.SVGProps<SVGSVGElement>) {
|
15
|
+
return (
|
16
|
+
<svg fill="none" height="24" viewBox="0 0 24 24" width="24" xmlns="http://www.w3.org/2000/svg" {...props}>
|
17
|
+
<path
|
18
|
+
d="m4 1.5c-.82843 0-1.5.67157-1.5 1.5v18c0 .8284.67157 1.5 1.5 1.5h16c.8284 0 1.5-.6716 1.5-1.5v-18c0-.82843-.6716-1.5-1.5-1.5z"
|
19
|
+
fill="#cee9d8"
|
20
|
+
stroke="#79c292"
|
21
|
+
/>
|
22
|
+
<g fill="#098934">
|
23
|
+
<rect height="1" rx=".5" width="6" x="6" y="8" />
|
24
|
+
<rect height="1" rx=".5" width="6" x="6" y="10" />
|
25
|
+
<rect height="1" rx=".5" width="12" x="6" y="12" />
|
26
|
+
<rect height="1" rx=".5" width="12" x="6" y="14" />
|
27
|
+
<rect height="1" rx=".5" width="12" x="6" y="16" />
|
28
|
+
<rect height="1" rx=".5" width="12" x="6" y="18" />
|
29
|
+
</g>
|
30
|
+
{!isDecorative && <title>page standard icon</title>}
|
31
|
+
</svg>
|
32
|
+
);
|
33
|
+
}
|
@@ -0,0 +1,34 @@
|
|
1
|
+
import React from 'react';
|
2
|
+
|
3
|
+
/**
|
4
|
+
* Renders the Pdf icon
|
5
|
+
* @param {React.SVGProps<SVGSVGElement>} props - The props for the Pdf component
|
6
|
+
* @returns {JSX.Element} - The Pdf component
|
7
|
+
* @example
|
8
|
+
* <Pdf />
|
9
|
+
* @example
|
10
|
+
* <Pdf height={24} width={24} />
|
11
|
+
* @example
|
12
|
+
* <Pdf className="custom-class" />
|
13
|
+
*/
|
14
|
+
export default function Pdf({ isDecorative, ...props }: { isDecorative: boolean } & React.SVGProps<SVGSVGElement>) {
|
15
|
+
return (
|
16
|
+
<svg fill="none" height="24" viewBox="0 0 24 24" width="24" xmlns="http://www.w3.org/2000/svg" {...props}>
|
17
|
+
<path
|
18
|
+
d="m15.9393 3.23223-.3515.35154.3515-.35154c-.4688-.46884-1.1047-.73223-1.7677-.73223h-8.1716c-.82843 0-1.5.67157-1.5 1.5v16c0 .8284.67157 1.5 1.5 1.5h12c.8284 0 1.5-.6716 1.5-1.5v-12.17157c0-.66304-.2634-1.29893-.7322-1.76777z"
|
19
|
+
fill="#f6d2d1"
|
20
|
+
stroke="#e88483"
|
21
|
+
/>
|
22
|
+
<path d="m14.5 3v3.5c0 .55228.4477 1 1 1h3.5" stroke="#e88483" />
|
23
|
+
<rect fill="#d72321" height="9" rx="2" width="17" y="11" />
|
24
|
+
<rect fill="#d72321" height="7" rx="1" width="13" x="2" y="12" />
|
25
|
+
<g stroke="#fff" strokeLinecap="round">
|
26
|
+
<path d="m3.5 17.5v-2m0 0v-1.8c0-.1105.08954-.2.2-.2h1c.55228 0 1 .4477 1 1 0 .5523-.44772 1-1 1z" />
|
27
|
+
<path d="m7.5 17.3v-3.6c0-.1105.08954-.2.2-.2h.3c.82843 0 1.5.6716 1.5 1.5v1c0 .8284-.67157 1.5-1.5 1.5h-.3c-.11046 0-.2-.0895-.2-.2z" />
|
28
|
+
<path d="m11.5 17.5v-3.8c0-.1105.0895-.2.2-.2h1.8" />
|
29
|
+
<path d="m11.5 15.5h1" />
|
30
|
+
</g>
|
31
|
+
{!isDecorative && <title>pdf icon</title>}
|
32
|
+
</svg>
|
33
|
+
);
|
34
|
+
}
|
@@ -0,0 +1,34 @@
|
|
1
|
+
import React from 'react';
|
2
|
+
|
3
|
+
/**
|
4
|
+
* Renders the Powerpoint icon
|
5
|
+
* @param {React.SVGProps<SVGSVGElement>} props - The props for the Powerpoint component
|
6
|
+
* @returns {JSX.Element} - The Powerpoint component
|
7
|
+
* @example
|
8
|
+
* <Powerpoint />
|
9
|
+
* @example
|
10
|
+
* <Powerpoint height={24} width={24} />
|
11
|
+
* @example
|
12
|
+
* <Powerpoint className="custom-class" />
|
13
|
+
*/
|
14
|
+
export default function Powerpoint({
|
15
|
+
isDecorative,
|
16
|
+
...props
|
17
|
+
}: { isDecorative: boolean } & React.SVGProps<SVGSVGElement>) {
|
18
|
+
return (
|
19
|
+
<svg fill="none" height="24" viewBox="0 0 24 24" width="24" xmlns="http://www.w3.org/2000/svg" {...props}>
|
20
|
+
<path
|
21
|
+
d="m15.9393 3.23223-.3515.35154.3515-.35154c-.4688-.46884-1.1047-.73223-1.7677-.73223h-8.1716c-.82843 0-1.5.67157-1.5 1.5v16c0 .8284.67157 1.5 1.5 1.5h12c.8284 0 1.5-.6716 1.5-1.5v-12.17157c0-.66304-.2634-1.29893-.7322-1.76777z"
|
22
|
+
fill="#e7e7e7"
|
23
|
+
stroke="#bcbcbc"
|
24
|
+
/>
|
25
|
+
<path d="m14.5 3v3.5c0 .55228.4477 1 1 1h3.5" stroke="#bcbcbc" />
|
26
|
+
<rect fill="#e96900" height="12" rx="2" width="12" y="8" />
|
27
|
+
<g stroke="#fff" strokeLinecap="round">
|
28
|
+
<path d="m3.5 11.5v5" />
|
29
|
+
<path d="m3.5 11.5h3.5c.33333 0 1.5 0 1.5 1.5s-1.16667 1.5-1.5 1.5h-3" />
|
30
|
+
</g>
|
31
|
+
{!isDecorative && <title>powerpoint icon</title>}
|
32
|
+
</svg>
|
33
|
+
);
|
34
|
+
}
|
@@ -0,0 +1,37 @@
|
|
1
|
+
import React from 'react';
|
2
|
+
|
3
|
+
/**
|
4
|
+
* Renders the Site icon
|
5
|
+
* @param {React.SVGProps<SVGSVGElement>} props - The props for the Site component
|
6
|
+
* @returns {JSX.Element} - The Site component
|
7
|
+
* @example
|
8
|
+
* <Site />
|
9
|
+
* @example
|
10
|
+
* <Site height={24} width={24} />
|
11
|
+
* @example
|
12
|
+
* <Site className="custom-class" />
|
13
|
+
*/
|
14
|
+
export default function Site({ isDecorative, ...props }: { isDecorative: boolean } & React.SVGProps<SVGSVGElement>) {
|
15
|
+
return (
|
16
|
+
<svg fill="none" height="24" viewBox="0 0 24 24" width="24" xmlns="http://www.w3.org/2000/svg" {...props}>
|
17
|
+
<circle cx="12" cy="12" fill="#cce2f5" r="10.5" stroke="#7db4e3" />
|
18
|
+
<path
|
19
|
+
d="m19.5 12c0 2.9434-.8684 5.5878-2.2475 7.4841-1.3795 1.8968-3.2427 3.0159-5.2525 3.0159-2.00976 0-3.87299-1.1191-5.25249-3.0159-1.37913-1.8963-2.24751-4.5407-2.24751-7.4841 0-2.94337.86838-5.58777 2.24751-7.48409 1.3795-1.8968 3.24273-3.01591 5.25249-3.01591 2.0098 0 3.873 1.11911 5.2525 3.01591 1.3791 1.89632 2.2475 4.54072 2.2475 7.48409z"
|
20
|
+
fill="#cce2f5"
|
21
|
+
stroke="#7db4e3"
|
22
|
+
/>
|
23
|
+
<path
|
24
|
+
d="m14.5 12c0 3.0063-.3329 5.7099-.8611 7.6466-.265.9719-.5718 1.7223-.8914 2.218-.334.5181-.5981.6354-.7475.6354s-.4135-.1173-.7475-.6354c-.3196-.4957-.6264-1.2461-.8914-2.218-.52822-1.9367-.8611-4.6403-.8611-7.6466 0-3.00626.33288-5.70993.8611-7.64662.265-.97192.5718-1.72231.8914-2.21799.334-.51806.5981-.63539.7475-.63539s.4135.11733.7475.63539c.3196.49568.6264 1.24607.8914 2.21799.5282 1.93669.8611 4.64036.8611 7.64662z"
|
25
|
+
fill="#cce2f5"
|
26
|
+
stroke="#7db4e3"
|
27
|
+
/>
|
28
|
+
<g fill="#7db4e3">
|
29
|
+
<path d="m2 14h20v1h-20z" />
|
30
|
+
<path d="m2 9h20v1h-20z" />
|
31
|
+
<path d="m5 4 2.5-1-.5 1h10l-.5-1 2.5 1 .5 1h-15z" />
|
32
|
+
<path d="m4 19h16l-.5 1-3 1 .5-1h-10l.5 1-3-1z" />
|
33
|
+
</g>
|
34
|
+
{!isDecorative && <title>site icon</title>}
|
35
|
+
</svg>
|
36
|
+
);
|
37
|
+
}
|
@@ -0,0 +1,27 @@
|
|
1
|
+
import React from 'react';
|
2
|
+
|
3
|
+
/**
|
4
|
+
* Renders the Video icon
|
5
|
+
* @param {React.SVGProps<SVGSVGElement>} props - The props for the Video component
|
6
|
+
* @returns {JSX.Element} - The Video component
|
7
|
+
* @example
|
8
|
+
* <Video />
|
9
|
+
* @example
|
10
|
+
* <Video height={24} width={24} />
|
11
|
+
* @example
|
12
|
+
* <Video className="custom-class" />
|
13
|
+
*/
|
14
|
+
export default function Video({ isDecorative, ...props }: { isDecorative: boolean } & React.SVGProps<SVGSVGElement>) {
|
15
|
+
return (
|
16
|
+
<svg fill="none" height="24" viewBox="0 0 24 24" width="24" xmlns="http://www.w3.org/2000/svg" {...props}>
|
17
|
+
<rect fill="#e0d9ef" height="15" rx="1.5" stroke="#ac98d5" width="21" x="1.5" y="4.5" />
|
18
|
+
<path
|
19
|
+
d="m9.5 15.2516v-6.50318c0-.38671.42019-.62704.7535-.43097l5.5277 3.25155c.3287.1934.3287.6686 0 .862l-5.5277 3.2516c-.33331.196-.7535-.0443-.7535-.431z"
|
20
|
+
fill="#ac98d5"
|
21
|
+
stroke="#6b47b4"
|
22
|
+
strokeLinecap="round"
|
23
|
+
/>
|
24
|
+
{!isDecorative && <title>video icon</title>}
|
25
|
+
</svg>
|
26
|
+
);
|
27
|
+
}
|
@@ -0,0 +1,30 @@
|
|
1
|
+
import React from 'react';
|
2
|
+
|
3
|
+
/**
|
4
|
+
* Renders the Word icon
|
5
|
+
* @param {React.SVGProps<SVGSVGElement>} props - The props for the Word component
|
6
|
+
* @returns {JSX.Element} - The Word component
|
7
|
+
* @example
|
8
|
+
* <Word />
|
9
|
+
* @example
|
10
|
+
* <Word isDecorative={false} />
|
11
|
+
* @example
|
12
|
+
* <Word height={24} width={24} />
|
13
|
+
* @example
|
14
|
+
* <Word className="custom-class" />
|
15
|
+
*/
|
16
|
+
export default function Word({ isDecorative, ...props }: { isDecorative: boolean } & React.SVGProps<SVGSVGElement>) {
|
17
|
+
return (
|
18
|
+
<svg fill="none" height="24" viewBox="0 0 24 24" width="24" xmlns="http://www.w3.org/2000/svg" {...props}>
|
19
|
+
<path
|
20
|
+
d="m15.9393 3.23223-.3515.35154.3515-.35154c-.4688-.46884-1.1047-.73223-1.7677-.73223h-8.1716c-.82843 0-1.5.67157-1.5 1.5v16c0 .8284.67157 1.5 1.5 1.5h12c.8284 0 1.5-.6716 1.5-1.5v-12.17157c0-.66304-.2634-1.29893-.7322-1.76777z"
|
21
|
+
fill="#e7e7e7"
|
22
|
+
stroke="#bcbcbc"
|
23
|
+
/>
|
24
|
+
<path d="m14.5 3v3.5c0 .55228.4477 1 1 1h3.5" stroke="#bcbcbc" />
|
25
|
+
<rect fill="#0774d2" height="12" rx="2" width="12" y="8" />
|
26
|
+
<path d="m2.5 11.5 1.5 5 2-5 2 5 1.5-5" stroke="#fff" strokeLinecap="round" strokeLinejoin="round" />
|
27
|
+
{!isDecorative && <title>word icon</title>}
|
28
|
+
</svg>
|
29
|
+
);
|
30
|
+
}
|
@@ -0,0 +1,12 @@
|
|
1
|
+
// Export all the icons from the MatrixResources folder
|
2
|
+
export { default as Audio } from './Audio';
|
3
|
+
export { default as Excel } from './Excel';
|
4
|
+
export { default as Folder } from './Folder';
|
5
|
+
export { default as GenericFile } from './GenericFile';
|
6
|
+
export { default as Image } from './Image';
|
7
|
+
export { default as Page } from './Page';
|
8
|
+
export { default as Pdf } from './Pdf';
|
9
|
+
export { default as Powerpoint } from './Powerpoint';
|
10
|
+
export { default as Site } from './Site';
|
11
|
+
export { default as Video } from './Video';
|
12
|
+
export { default as Word } from './Word';
|
@@ -0,0 +1,244 @@
|
|
1
|
+
import React from 'react';
|
2
|
+
import { screen, render, waitFor } from '@testing-library/react';
|
3
|
+
import userEvent from '@testing-library/user-event';
|
4
|
+
|
5
|
+
import ModalTrigger from './ModalTrigger';
|
6
|
+
|
7
|
+
describe('Modal', () => {
|
8
|
+
it('Modal is closed by default', async () => {
|
9
|
+
render(
|
10
|
+
<div>
|
11
|
+
<ModalTrigger label={'Open testing modal'} showLabel>
|
12
|
+
{(onClose, titleProps) => (
|
13
|
+
<div data-testingid="modal">
|
14
|
+
<div {...titleProps}>Testing</div>
|
15
|
+
<button type="button" onClick={onClose}>
|
16
|
+
Close
|
17
|
+
</button>
|
18
|
+
</div>
|
19
|
+
)}
|
20
|
+
</ModalTrigger>
|
21
|
+
<div style={{ height: '150vh' }} />
|
22
|
+
</div>,
|
23
|
+
);
|
24
|
+
expect(screen.queryByTestId('modal')).toBeFalsy();
|
25
|
+
});
|
26
|
+
|
27
|
+
it('Modal opens when triggered', async () => {
|
28
|
+
render(
|
29
|
+
<div>
|
30
|
+
<ModalTrigger label={'Open testing modal'} showLabel>
|
31
|
+
{(onClose, titleProps) => (
|
32
|
+
<div data-testid="modal">
|
33
|
+
<div {...titleProps}>Testing</div>
|
34
|
+
<button type="button" onClick={onClose}>
|
35
|
+
Close
|
36
|
+
</button>
|
37
|
+
</div>
|
38
|
+
)}
|
39
|
+
</ModalTrigger>
|
40
|
+
<div style={{ height: '150vh' }} />
|
41
|
+
</div>,
|
42
|
+
);
|
43
|
+
|
44
|
+
const user = userEvent.setup();
|
45
|
+
user.click(screen.getByText('Open testing modal'));
|
46
|
+
|
47
|
+
await waitFor(() => {
|
48
|
+
expect(screen.queryByTestId('modal')).toBeTruthy();
|
49
|
+
});
|
50
|
+
});
|
51
|
+
|
52
|
+
it('Clicking outside the modal closes it', async () => {
|
53
|
+
render(
|
54
|
+
<div data-testid="outside">
|
55
|
+
<ModalTrigger label={'Open testing modal'} showLabel>
|
56
|
+
{(onClose, titleProps) => (
|
57
|
+
<div data-testid="modal">
|
58
|
+
<div {...titleProps}>Testing</div>
|
59
|
+
<button type="button" onClick={onClose}>
|
60
|
+
Close
|
61
|
+
</button>
|
62
|
+
</div>
|
63
|
+
)}
|
64
|
+
</ModalTrigger>
|
65
|
+
<div style={{ height: '150vh' }} />
|
66
|
+
</div>,
|
67
|
+
);
|
68
|
+
|
69
|
+
const user = userEvent.setup();
|
70
|
+
user.click(screen.getByText('Open testing modal'));
|
71
|
+
|
72
|
+
await waitFor(() => {
|
73
|
+
expect(screen.queryByTestId('modal')).toBeTruthy();
|
74
|
+
});
|
75
|
+
|
76
|
+
user.click(screen.getByTestId('outside'));
|
77
|
+
|
78
|
+
await waitFor(() => {
|
79
|
+
expect(screen.queryByTestId('modal')).toBeFalsy();
|
80
|
+
});
|
81
|
+
});
|
82
|
+
|
83
|
+
it('ESC closes modal', async () => {
|
84
|
+
render(
|
85
|
+
<div data-testid="outside">
|
86
|
+
<ModalTrigger label={'Open testing modal'} showLabel>
|
87
|
+
{(onClose, titleProps) => (
|
88
|
+
<div data-testid="modal">
|
89
|
+
<div {...titleProps}>Testing</div>
|
90
|
+
<button type="button" onClick={onClose}>
|
91
|
+
Close
|
92
|
+
</button>
|
93
|
+
</div>
|
94
|
+
)}
|
95
|
+
</ModalTrigger>
|
96
|
+
<div style={{ height: '150vh' }} />
|
97
|
+
</div>,
|
98
|
+
);
|
99
|
+
|
100
|
+
const user = userEvent.setup();
|
101
|
+
user.click(screen.getByText('Open testing modal'));
|
102
|
+
|
103
|
+
await waitFor(() => {
|
104
|
+
expect(screen.queryByTestId('modal')).toBeTruthy();
|
105
|
+
});
|
106
|
+
|
107
|
+
user.type(screen.getByTestId('modal'), '{escape}');
|
108
|
+
|
109
|
+
await waitFor(() => {
|
110
|
+
expect(screen.queryByTestId('modal')).toBeFalsy();
|
111
|
+
});
|
112
|
+
});
|
113
|
+
|
114
|
+
it('Invoking onClose function closes modal', async () => {
|
115
|
+
render(
|
116
|
+
<div>
|
117
|
+
<ModalTrigger label={'Open testing modal'} showLabel>
|
118
|
+
{(onClose, titleProps) => (
|
119
|
+
<div data-testid="modal">
|
120
|
+
<div {...titleProps}>Testing</div>
|
121
|
+
<button data-testid="closeButton" type="button" onClick={onClose}>
|
122
|
+
Close
|
123
|
+
</button>
|
124
|
+
</div>
|
125
|
+
)}
|
126
|
+
</ModalTrigger>
|
127
|
+
<div style={{ height: '150vh' }} />
|
128
|
+
</div>,
|
129
|
+
);
|
130
|
+
|
131
|
+
const user = userEvent.setup();
|
132
|
+
user.click(screen.getByText('Open testing modal'));
|
133
|
+
|
134
|
+
await waitFor(() => {
|
135
|
+
expect(screen.queryByTestId('modal')).toBeTruthy();
|
136
|
+
});
|
137
|
+
|
138
|
+
user.click(screen.getByTestId('closeButton'));
|
139
|
+
|
140
|
+
await waitFor(() => {
|
141
|
+
expect(screen.queryByTestId('modal')).toBeFalsy();
|
142
|
+
});
|
143
|
+
});
|
144
|
+
|
145
|
+
it('Focus is trapped within modal', async () => {
|
146
|
+
render(
|
147
|
+
<div>
|
148
|
+
<button />
|
149
|
+
<ModalTrigger label={'Open testing modal'} showLabel>
|
150
|
+
{(onClose, titleProps) => (
|
151
|
+
<div data-testid="modal">
|
152
|
+
<div {...titleProps}>Testing</div>
|
153
|
+
<button data-testid="closeButton" type="button" onClick={onClose}>
|
154
|
+
Close
|
155
|
+
</button>
|
156
|
+
</div>
|
157
|
+
)}
|
158
|
+
</ModalTrigger>
|
159
|
+
<button />
|
160
|
+
<div style={{ height: '150vh' }} />
|
161
|
+
</div>,
|
162
|
+
);
|
163
|
+
|
164
|
+
const user = userEvent.setup();
|
165
|
+
user.click(screen.getByText('Open testing modal'));
|
166
|
+
|
167
|
+
await waitFor(() => {
|
168
|
+
expect(screen.queryByTestId('modal')).toBeTruthy();
|
169
|
+
});
|
170
|
+
|
171
|
+
user.type(screen.getByTestId('modal'), '{tab}');
|
172
|
+
user.type(screen.getByTestId('modal'), '{tab}');
|
173
|
+
|
174
|
+
await waitFor(() => {
|
175
|
+
expect(screen.queryByTestId('closeButton')).toHaveFocus();
|
176
|
+
});
|
177
|
+
});
|
178
|
+
|
179
|
+
it('Focus should start on the dialog', async () => {
|
180
|
+
render(
|
181
|
+
<div>
|
182
|
+
<button />
|
183
|
+
<ModalTrigger label={'Open testing modal'} showLabel>
|
184
|
+
{(onClose, titleProps) => (
|
185
|
+
<div data-testid="modal">
|
186
|
+
<div data-testid="title" {...titleProps}>
|
187
|
+
Testing
|
188
|
+
</div>
|
189
|
+
<button data-testid="closeButton" type="button" onClick={onClose}>
|
190
|
+
Close
|
191
|
+
</button>
|
192
|
+
</div>
|
193
|
+
)}
|
194
|
+
</ModalTrigger>
|
195
|
+
<button />
|
196
|
+
<div style={{ height: '150vh' }} />
|
197
|
+
</div>,
|
198
|
+
);
|
199
|
+
|
200
|
+
const user = userEvent.setup();
|
201
|
+
user.click(screen.getByText('Open testing modal'));
|
202
|
+
|
203
|
+
await waitFor(() => {
|
204
|
+
expect(screen.queryByTestId('modal')).toBeTruthy();
|
205
|
+
expect(screen.queryByRole('dialog')).toHaveFocus();
|
206
|
+
});
|
207
|
+
});
|
208
|
+
|
209
|
+
it('Title props provides id for dialog link', async () => {
|
210
|
+
let titleId: string | undefined = '';
|
211
|
+
render(
|
212
|
+
<div>
|
213
|
+
<button />
|
214
|
+
<ModalTrigger label={'Open testing modal'} showLabel>
|
215
|
+
{(onClose, titleProps) => {
|
216
|
+
titleId = titleProps.id;
|
217
|
+
|
218
|
+
return (
|
219
|
+
<div data-testid="modal">
|
220
|
+
<div data-testid="title" {...titleProps}>
|
221
|
+
Testing
|
222
|
+
</div>
|
223
|
+
<button data-testid="closeButton" type="button" onClick={onClose}>
|
224
|
+
Close
|
225
|
+
</button>
|
226
|
+
</div>
|
227
|
+
);
|
228
|
+
}}
|
229
|
+
</ModalTrigger>
|
230
|
+
<button />
|
231
|
+
<div style={{ height: '150vh' }} />
|
232
|
+
</div>,
|
233
|
+
);
|
234
|
+
|
235
|
+
const user = userEvent.setup();
|
236
|
+
user.click(screen.getByText('Open testing modal'));
|
237
|
+
|
238
|
+
await waitFor(() => {
|
239
|
+
expect(screen.queryByTestId('modal')).toBeTruthy();
|
240
|
+
expect(screen.queryByTestId('title')).toHaveAttribute('id'); // Title was provided an id by 'titleProps'
|
241
|
+
expect(screen.queryByRole('dialog')).toHaveAttribute('aria-labelledby', titleId); // 'titleProps' id is added to the dialog label
|
242
|
+
});
|
243
|
+
});
|
244
|
+
});
|
@@ -0,0 +1,58 @@
|
|
1
|
+
import React, { useRef } from 'react';
|
2
|
+
|
3
|
+
import { Overlay, useModalOverlay, useDialog } from 'react-aria';
|
4
|
+
import { OverlayTriggerState } from 'react-stately';
|
5
|
+
import { DOMAttributes, FocusableElement } from '@react-types/shared';
|
6
|
+
|
7
|
+
/*
|
8
|
+
This has to be a separate element otherwise the focus trap fails. Assuming this is because it needs
|
9
|
+
to fit inside the 'Overlay' as a form of context.
|
10
|
+
*/
|
11
|
+
function ModalContent({
|
12
|
+
children,
|
13
|
+
...props
|
14
|
+
}: {
|
15
|
+
children: (titleProps: DOMAttributes<FocusableElement>) => React.ReactElement;
|
16
|
+
}) {
|
17
|
+
const ref = useRef<HTMLDivElement>(null);
|
18
|
+
const { dialogProps, titleProps } = useDialog(props, ref);
|
19
|
+
|
20
|
+
return (
|
21
|
+
<div
|
22
|
+
{...dialogProps}
|
23
|
+
ref={ref}
|
24
|
+
className="z-50 relative bg-white rounded-lg h-screen lg:h-[calc(100vh-3.5rem)] w-screen max-w-screen-lg"
|
25
|
+
>
|
26
|
+
{children(titleProps)}
|
27
|
+
</div>
|
28
|
+
);
|
29
|
+
}
|
30
|
+
|
31
|
+
export type ModalProps = {
|
32
|
+
isDismissable?: boolean;
|
33
|
+
state: OverlayTriggerState;
|
34
|
+
overlayProps: DOMAttributes<FocusableElement>;
|
35
|
+
children: (titleProps: DOMAttributes<FocusableElement>) => React.ReactElement; // Returns the title props from the 'ModalContent'
|
36
|
+
};
|
37
|
+
|
38
|
+
function Modal({ isDismissable, state, overlayProps, children, ...props }: ModalProps) {
|
39
|
+
const ref = useRef<HTMLDivElement>(null);
|
40
|
+
const { modalProps, underlayProps } = useModalOverlay({ isDismissable, ...props }, state, ref);
|
41
|
+
|
42
|
+
return (
|
43
|
+
<Overlay>
|
44
|
+
<div className="squiz-rb-scope">
|
45
|
+
<div
|
46
|
+
{...underlayProps}
|
47
|
+
className="h-full z-[9999] fixed inset-0 before:z-40 before:fixed before:inset-0 before:bg-black before:bg-opacity-25"
|
48
|
+
>
|
49
|
+
<div {...modalProps} ref={ref} className="h-full flex items-center justify-center">
|
50
|
+
<ModalContent {...overlayProps}>{(titleProps) => children(titleProps)}</ModalContent>
|
51
|
+
</div>
|
52
|
+
</div>
|
53
|
+
</div>
|
54
|
+
</Overlay>
|
55
|
+
);
|
56
|
+
}
|
57
|
+
|
58
|
+
export default Modal;
|
@@ -0,0 +1,33 @@
|
|
1
|
+
import React from 'react';
|
2
|
+
import { StoryFn, Meta } from '@storybook/react';
|
3
|
+
|
4
|
+
import ModalTrigger from './ModalTrigger';
|
5
|
+
|
6
|
+
export default {
|
7
|
+
title: 'Modal',
|
8
|
+
component: ModalTrigger,
|
9
|
+
} as Meta<typeof ModalTrigger>;
|
10
|
+
|
11
|
+
const Template: StoryFn<typeof ModalTrigger> = ({ label }) => {
|
12
|
+
return (
|
13
|
+
<>
|
14
|
+
<ModalTrigger label={label} showLabel>
|
15
|
+
{(onClose, titleProps) => (
|
16
|
+
<div>
|
17
|
+
<div {...titleProps}>Testing</div>
|
18
|
+
<button type="button" onClick={onClose}>
|
19
|
+
Close
|
20
|
+
</button>
|
21
|
+
</div>
|
22
|
+
)}
|
23
|
+
</ModalTrigger>
|
24
|
+
<div style={{ height: '150vh' }} />
|
25
|
+
</>
|
26
|
+
);
|
27
|
+
};
|
28
|
+
|
29
|
+
export const Primary = Template.bind({});
|
30
|
+
|
31
|
+
Primary.args = {
|
32
|
+
label: 'Resource Browser Modal',
|
33
|
+
};
|