@grantbii/design-system 1.0.56 → 1.0.58
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/core/molecules/FileDrop.js +1 -4
- package/core/organisms/GrantMatch.d.ts +5 -9
- package/core/organisms/GrantMatch.js +74 -28
- package/package.json +1 -1
- package/stories/organisms/GrantMatch.stories.d.ts +4 -4
- package/stories/organisms/GrantMatch.stories.js +27 -13
- package/tsconfig.tsbuildinfo +1 -1
|
@@ -107,10 +107,7 @@ export const useFileDrop = (initialFiles = [], maxFiles = DEFAULT_MAX_FILES, max
|
|
|
107
107
|
errorMessage,
|
|
108
108
|
};
|
|
109
109
|
};
|
|
110
|
-
const anyFileTooLarge = (files, maxSizeMB) => files.some((file) =>
|
|
111
|
-
console.log("file size:", file.size);
|
|
112
|
-
return file.size > convertMegabytesToBytes(maxSizeMB);
|
|
113
|
-
});
|
|
110
|
+
const anyFileTooLarge = (files, maxSizeMB) => files.some((file) => file.size > convertMegabytesToBytes(maxSizeMB));
|
|
114
111
|
const convertMegabytesToBytes = (megabytes) => megabytes * 1024 * 1024;
|
|
115
112
|
const combineFilesWithoutDuplicates = (oldFiles, newFiles) => {
|
|
116
113
|
const newFileNames = newFiles.map((file) => file.name);
|
|
@@ -1,18 +1,14 @@
|
|
|
1
1
|
import { GrantMatchQuery } from "@grantbii/ui-base/match/models";
|
|
2
|
-
type GrantMatchProps = {
|
|
3
|
-
|
|
4
|
-
onPerformGrantMatch: (newQuery: GrantMatchQuery) => void;
|
|
5
|
-
removeQueryFile: (fileName: string) => void;
|
|
6
|
-
removeQueryText: () => void;
|
|
7
|
-
resetQuery: () => void;
|
|
8
|
-
isModalFullScreen?: boolean;
|
|
2
|
+
type GrantMatchProps = GrantMatchQueryProps & {
|
|
3
|
+
isSmallerThanLaptop?: boolean;
|
|
9
4
|
};
|
|
10
|
-
declare const GrantMatch: ({ query,
|
|
5
|
+
declare const GrantMatch: ({ query, updateQuery, removeQueryFile, removeQueryText, resetQuery, isSmallerThanLaptop, }: GrantMatchProps) => import("react/jsx-runtime").JSX.Element;
|
|
11
6
|
export default GrantMatch;
|
|
12
|
-
|
|
7
|
+
type GrantMatchQueryProps = {
|
|
13
8
|
query: GrantMatchQuery;
|
|
14
9
|
updateQuery: (newQuery: GrantMatchQuery) => void;
|
|
15
10
|
removeQueryFile: (fileName: string) => void;
|
|
16
11
|
removeQueryText: () => void;
|
|
17
12
|
resetQuery: () => void;
|
|
18
13
|
};
|
|
14
|
+
export declare const useGrantMatchQueryItems: (performGrantMatch: (newQuery: GrantMatchQuery) => void, resetGrantMatch: () => void) => GrantMatchQueryProps;
|
|
@@ -5,26 +5,54 @@ import styled from "styled-components";
|
|
|
5
5
|
import { Badge, Button, Textarea } from "../atoms";
|
|
6
6
|
import { Colors, Icons } from "../foundations";
|
|
7
7
|
import { FileDrop, Modal, useFileDrop, useModal } from "../molecules";
|
|
8
|
-
const GrantMatch = ({ query,
|
|
8
|
+
const GrantMatch = ({ query, updateQuery, removeQueryFile, removeQueryText, resetQuery, isSmallerThanLaptop, }) => {
|
|
9
9
|
const { showModal, openModal, closeModal } = useModal();
|
|
10
10
|
const isActive = isGrantMatchActive(query);
|
|
11
|
-
const
|
|
12
|
-
|
|
11
|
+
const updateActiveQuery = (newQuery) => {
|
|
12
|
+
updateQuery(newQuery);
|
|
13
13
|
closeModal();
|
|
14
14
|
};
|
|
15
|
-
return (_jsxs(
|
|
15
|
+
return (_jsxs(BaseGrantMatch, { children: [_jsx(GrantMatchButtons, { isActive: isActive, onClickMatch: () => openModal(), onClickReset: () => resetQuery(), isSmallerThanLaptop: isSmallerThanLaptop }), isActive ? (_jsxs(QueryItemsRow, { children: [_jsx(QueryItems, { activeQuery: query, removeQueryFile: removeQueryFile, removeQueryText: removeQueryText }), isSmallerThanLaptop ? (_jsx(ResetButton, { onClick: () => resetQuery() })) : (_jsx(_Fragment, {}))] })) : (_jsx(_Fragment, {})), showModal ? (_jsx(GrantMatchModal, { activeQuery: query, updateActiveQuery: updateActiveQuery, onClickCancel: () => closeModal(), isFullScreen: isSmallerThanLaptop })) : (_jsx(_Fragment, {}))] }));
|
|
16
16
|
};
|
|
17
17
|
export default GrantMatch;
|
|
18
|
-
const
|
|
19
|
-
export const useGrantMatchQueryItems = () => {
|
|
18
|
+
export const useGrantMatchQueryItems = (performGrantMatch, resetGrantMatch) => {
|
|
20
19
|
const [query, setQuery] = useState(() => (Object.assign({}, BLANK_GRANT_MATCH_QUERY)));
|
|
21
|
-
const updateQuery = (newQuery) =>
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
20
|
+
const updateQuery = (newQuery) => {
|
|
21
|
+
setQuery(Object.assign({}, newQuery));
|
|
22
|
+
if (isGrantMatchActive(newQuery)) {
|
|
23
|
+
performGrantMatch(newQuery);
|
|
24
|
+
}
|
|
25
|
+
else {
|
|
26
|
+
resetGrantMatch();
|
|
27
|
+
}
|
|
28
|
+
};
|
|
29
|
+
const removeQueryFile = (fileName) => {
|
|
30
|
+
const newQuery = {
|
|
31
|
+
files: query.files.filter((file) => file.name !== fileName),
|
|
32
|
+
text: query.text,
|
|
33
|
+
};
|
|
34
|
+
updateQuery(newQuery);
|
|
35
|
+
if (isGrantMatchActive(newQuery)) {
|
|
36
|
+
performGrantMatch(newQuery);
|
|
37
|
+
}
|
|
38
|
+
else {
|
|
39
|
+
resetGrantMatch();
|
|
40
|
+
}
|
|
41
|
+
};
|
|
42
|
+
const removeQueryText = () => {
|
|
43
|
+
const newQuery = { files: query.files, text: "" };
|
|
44
|
+
updateQuery(newQuery);
|
|
45
|
+
if (isGrantMatchActive(newQuery)) {
|
|
46
|
+
performGrantMatch(newQuery);
|
|
47
|
+
}
|
|
48
|
+
else {
|
|
49
|
+
resetGrantMatch();
|
|
50
|
+
}
|
|
51
|
+
};
|
|
52
|
+
const resetQuery = () => {
|
|
53
|
+
setQuery(Object.assign({}, BLANK_GRANT_MATCH_QUERY));
|
|
54
|
+
resetGrantMatch();
|
|
55
|
+
};
|
|
28
56
|
return {
|
|
29
57
|
query,
|
|
30
58
|
updateQuery,
|
|
@@ -33,49 +61,65 @@ export const useGrantMatchQueryItems = () => {
|
|
|
33
61
|
resetQuery,
|
|
34
62
|
};
|
|
35
63
|
};
|
|
36
|
-
const
|
|
64
|
+
const BLANK_GRANT_MATCH_QUERY = { files: [], text: "" };
|
|
65
|
+
const BaseGrantMatch = styled.div `
|
|
37
66
|
display: flex;
|
|
38
67
|
flex-direction: column;
|
|
39
68
|
gap: 8px;
|
|
40
69
|
|
|
41
|
-
padding: 16px 16px 0px 16px;
|
|
42
|
-
|
|
43
70
|
width: 100%;
|
|
44
71
|
max-width: 100vw;
|
|
45
72
|
`;
|
|
46
|
-
const GrantMatchButtons = ({ isActive, onClickMatch, onClickReset, }) => (_jsxs(Buttons, { children: [_jsx(GrantMatchButton, { isActive: isActive, onClick: onClickMatch }), isActive ? (_jsx(
|
|
73
|
+
const GrantMatchButtons = ({ isActive, onClickMatch, onClickReset, isSmallerThanLaptop, }) => (_jsxs(Buttons, { children: [_jsx(GrantMatchButton, { isActive: isActive, isSmallerThanLaptop: isSmallerThanLaptop, onClick: onClickMatch }), !isSmallerThanLaptop && isActive ? (_jsx(ResetButton, { onClick: onClickReset })) : (_jsx(_Fragment, {}))] }));
|
|
47
74
|
const Buttons = styled.div `
|
|
48
75
|
display: flex;
|
|
49
76
|
align-items: center;
|
|
50
77
|
gap: 8px;
|
|
51
78
|
`;
|
|
52
|
-
const GrantMatchButton = ({ isActive, onClick }) => (_jsxs(BaseGrantMatchButton, { type: "button", "$isActive": isActive, onClick: onClick, children: [_jsx(Icons.GrantMatchIcon, { size: 20 }), _jsx("p", { children: "Find grants that match your needs" }), _jsx(Icons.MagnifyingGlassIcon, { size: 20 })] }));
|
|
79
|
+
const GrantMatchButton = ({ isActive, onClick, isSmallerThanLaptop, }) => (_jsxs(BaseGrantMatchButton, { type: "button", "$isSmallerThanLaptop": isSmallerThanLaptop, "$isActive": isActive, onClick: onClick, children: [_jsxs(GrantMatchButtonContent, { children: [_jsx(Icons.GrantMatchIcon, { size: 20 }), _jsx("p", { children: "Find grants that match your needs" })] }), _jsx(Icons.MagnifyingGlassIcon, { size: 20 })] }));
|
|
53
80
|
const BaseGrantMatchButton = styled.button `
|
|
54
81
|
display: flex;
|
|
55
82
|
align-items: center;
|
|
56
|
-
|
|
83
|
+
justify-content: space-between;
|
|
84
|
+
gap: 16px;
|
|
57
85
|
|
|
58
|
-
height: 20px;
|
|
59
86
|
padding: 10px 16px;
|
|
60
|
-
|
|
87
|
+
|
|
88
|
+
height: 20px;
|
|
89
|
+
width: ${({ $isSmallerThanLaptop = false }) => $isSmallerThanLaptop ? "100%" : "auto"};
|
|
61
90
|
|
|
62
91
|
font-size: 14px;
|
|
63
92
|
font-weight: 500;
|
|
64
93
|
|
|
65
|
-
color: ${Colors.typography.blackMedium};
|
|
66
94
|
background-color: ${Colors.base.white};
|
|
95
|
+
color: ${Colors.typography.blackMedium};
|
|
96
|
+
|
|
67
97
|
border: 1px solid
|
|
68
98
|
${({ $isActive }) => $isActive ? Colors.accent.yellow1 : Colors.neutral.grey3};
|
|
99
|
+
border-radius: 200px;
|
|
100
|
+
`;
|
|
101
|
+
const GrantMatchButtonContent = styled.div `
|
|
102
|
+
display: flex;
|
|
103
|
+
align-items: center;
|
|
104
|
+
gap: 8px;
|
|
69
105
|
`;
|
|
70
|
-
const
|
|
106
|
+
const ResetButton = ({ onClick }) => (_jsx(Button, { text: "Reset", onClick: onClick, color: Colors.typography.blackMedium, underline: true }));
|
|
107
|
+
const QueryItemsRow = styled.div `
|
|
108
|
+
display: flex;
|
|
109
|
+
align-items: center;
|
|
110
|
+
justify-content: space-between;
|
|
111
|
+
`;
|
|
112
|
+
const QueryItems = ({ activeQuery, removeQueryFile, removeQueryText, }) => (_jsxs(BaseQueryItems, { children: [activeQuery.files.map((file) => {
|
|
71
113
|
var _a;
|
|
72
114
|
return (_jsx(Badge, { text: file.name, Icon: (_a = FILE_TYPE_ICON_MAP[file.type]) !== null && _a !== void 0 ? _a : Icons.FileIcon, onClickClose: () => removeQueryFile(file.name), textWidthPixels: 160 }, file.name));
|
|
73
|
-
}),
|
|
115
|
+
}), activeQuery.text === "" ? (_jsx(_Fragment, {})) : (_jsx(Badge, { text: "Additional Information", Icon: Icons.TextAaIcon, onClickClose: () => removeQueryText(), textWidthPixels: 180 }, "additional-information-query-item"))] }));
|
|
74
116
|
const BaseQueryItems = styled.div `
|
|
75
117
|
display: flex;
|
|
76
118
|
align-items: center;
|
|
77
119
|
gap: 8px;
|
|
78
120
|
|
|
121
|
+
width: 100%;
|
|
122
|
+
|
|
79
123
|
overflow-x: auto;
|
|
80
124
|
|
|
81
125
|
/* hide scrollbar but still allow for scrolling */
|
|
@@ -84,14 +128,16 @@ const BaseQueryItems = styled.div `
|
|
|
84
128
|
::-webkit-scrollbar {
|
|
85
129
|
display: none;
|
|
86
130
|
}
|
|
131
|
+
|
|
132
|
+
/* TODO: fade effect on overflow-x */
|
|
87
133
|
`;
|
|
88
134
|
const FILE_TYPE_ICON_MAP = {
|
|
89
135
|
"application/pdf": Icons.FilePdfIcon,
|
|
90
136
|
};
|
|
91
|
-
const GrantMatchModal = ({
|
|
92
|
-
const { files, uploadFiles, removeFile } = useFileDrop(
|
|
93
|
-
const [text, setText] = useState(
|
|
94
|
-
return (_jsx(Modal, { header: _jsx(Header, {}), content: _jsx(Content, { files: files, uploadFiles: uploadFiles, removeFile: removeFile, queryText: text, updateQueryText: (newText) => setText(newText) }), footer: _jsx(Button, { text: "Find My Grants", onClick: () =>
|
|
137
|
+
const GrantMatchModal = ({ activeQuery, updateActiveQuery, onClickCancel, isFullScreen, }) => {
|
|
138
|
+
const { files, uploadFiles, removeFile } = useFileDrop(activeQuery.files);
|
|
139
|
+
const [text, setText] = useState(activeQuery.text);
|
|
140
|
+
return (_jsx(Modal, { header: _jsx(Header, {}), content: _jsx(Content, { files: files, uploadFiles: uploadFiles, removeFile: removeFile, queryText: text, updateQueryText: (newText) => setText(newText) }), footer: _jsx(Button, { text: "Find My Grants", onClick: () => updateActiveQuery({ files, text }), backgroundColor: Colors.accent.yellow1 }), onClickCancel: onClickCancel, isFullScreen: isFullScreen, width: "480px" }));
|
|
95
141
|
};
|
|
96
142
|
const Header = () => (_jsxs(BaseHeader, { children: [_jsx(Icons.GrantMatchIcon, { size: 24 }), _jsx("div", { children: "Grant Match" })] }));
|
|
97
143
|
const BaseHeader = styled.div `
|
package/package.json
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import { Meta, StoryObj } from "@storybook/nextjs-vite";
|
|
2
2
|
type GrantMatchExampleProps = {
|
|
3
|
-
|
|
3
|
+
isMobile?: boolean;
|
|
4
4
|
};
|
|
5
|
-
declare const GrantMatchExample: ({
|
|
5
|
+
declare const GrantMatchExample: ({ isMobile }: GrantMatchExampleProps) => import("react/jsx-runtime").JSX.Element;
|
|
6
6
|
declare const meta: Meta<typeof GrantMatchExample>;
|
|
7
7
|
export default meta;
|
|
8
8
|
type Story = StoryObj<typeof meta>;
|
|
9
|
-
export declare const
|
|
10
|
-
export declare const
|
|
9
|
+
export declare const Desktop: Story;
|
|
10
|
+
export declare const Mobile: Story;
|
|
@@ -1,17 +1,31 @@
|
|
|
1
|
-
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
-
import { GrantMatch } from "@/.";
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { Colors, GrantMatch } from "@/.";
|
|
3
3
|
import { useGrantMatchQueryItems } from "@/core/organisms/GrantMatch";
|
|
4
|
+
import { useState } from "react";
|
|
4
5
|
import styled from "styled-components";
|
|
5
|
-
const GrantMatchExample = ({
|
|
6
|
-
const
|
|
7
|
-
const
|
|
8
|
-
|
|
9
|
-
|
|
6
|
+
const GrantMatchExample = ({ isMobile }) => {
|
|
7
|
+
const [status, setStatus] = useState("pending query");
|
|
8
|
+
const performGrantMatch = (newQuery) => {
|
|
9
|
+
const fileNames = newQuery.files.map((file) => file.name).join(", ");
|
|
10
|
+
setStatus(`finding grants using files [${fileNames}] and text [${newQuery.text}]`);
|
|
11
|
+
setTimeout(() => setStatus("found grants"), 3000);
|
|
10
12
|
};
|
|
11
|
-
|
|
13
|
+
const resetGrantMatch = () => setStatus("pending query");
|
|
14
|
+
const grantMatchQueryProps = useGrantMatchQueryItems(performGrantMatch, resetGrantMatch);
|
|
15
|
+
return (_jsxs(Container, { "$isMobile": isMobile, children: [_jsx(GrantMatch, Object.assign({}, grantMatchQueryProps, { isSmallerThanLaptop: isMobile })), _jsxs("p", { children: ["Status: ", status] })] }));
|
|
12
16
|
};
|
|
13
17
|
const Container = styled.div `
|
|
14
|
-
|
|
18
|
+
display: flex;
|
|
19
|
+
flex-direction: column;
|
|
20
|
+
gap: 8px;
|
|
21
|
+
|
|
22
|
+
padding: 16px;
|
|
23
|
+
|
|
24
|
+
width: ${({ $isMobile = false }) => ($isMobile ? "360px" : "90vw")};
|
|
25
|
+
height: ${({ $isMobile = false }) => ($isMobile ? "600px" : "100vh")};
|
|
26
|
+
|
|
27
|
+
border: ${({ $isMobile = false }) => $isMobile ? `1px solid ${Colors.neutral.grey2}` : "none"};
|
|
28
|
+
border-radius: 32px;
|
|
15
29
|
`;
|
|
16
30
|
const meta = {
|
|
17
31
|
title: "Organisms/Grant Match",
|
|
@@ -22,9 +36,9 @@ const meta = {
|
|
|
22
36
|
},
|
|
23
37
|
};
|
|
24
38
|
export default meta;
|
|
25
|
-
export const
|
|
26
|
-
args: {},
|
|
39
|
+
export const Desktop = {
|
|
40
|
+
args: { isMobile: false },
|
|
27
41
|
};
|
|
28
|
-
export const
|
|
29
|
-
args: {
|
|
42
|
+
export const Mobile = {
|
|
43
|
+
args: { isMobile: true },
|
|
30
44
|
};
|