@grantbii/design-system 1.3.0 → 1.3.1
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/atoms/shared.d.ts +4 -0
- package/core/atoms/shared.js +6 -1
- package/core/atoms/shared.js.map +1 -1
- package/core/molecules/FileDrop.js +7 -5
- package/core/molecules/FileDrop.js.map +1 -1
- package/core/organisms/GrantMatch/ActiveQueryFiles.js +1 -3
- package/core/organisms/GrantMatch/ActiveQueryFiles.js.map +1 -1
- package/package.json +2 -2
- package/stories/atoms/Input.stories.js +2 -2
- package/stories/atoms/Input.stories.js.map +1 -1
- package/tsconfig.tsbuildinfo +1 -1
package/core/atoms/shared.d.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { Icons } from "../foundations";
|
|
1
2
|
export declare const BaseButton: import("styled-components/dist/types").IStyledComponentBase<"web", import("styled-components/dist/types").Substitute<import("react").DetailedHTMLProps<import("react").HTMLAttributes<HTMLDivElement>, HTMLDivElement>, {
|
|
2
3
|
$underline?: boolean;
|
|
3
4
|
$backgroundColor?: string;
|
|
@@ -6,3 +7,6 @@ export declare const BaseButton: import("styled-components/dist/types").IStyledC
|
|
|
6
7
|
}>> & string;
|
|
7
8
|
export declare const LabelledInput: import("styled-components/dist/types").IStyledComponentBase<"web", import("styled-components").FastOmit<import("react").DetailedHTMLProps<import("react").HTMLAttributes<HTMLDivElement>, HTMLDivElement>, never>> & string;
|
|
8
9
|
export declare const InputValidation: import("styled-components").RuleSet<object>;
|
|
10
|
+
export declare const FILE_TYPE_ICON_MAP: {
|
|
11
|
+
[mimeType: string]: Icons.Icon;
|
|
12
|
+
};
|
package/core/atoms/shared.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import styled, { css } from "styled-components";
|
|
2
|
-
import { Colors } from "../foundations";
|
|
2
|
+
import { Colors, Icons } from "../foundations";
|
|
3
3
|
export const BaseButton = styled.div `
|
|
4
4
|
display: flex;
|
|
5
5
|
justify-content: center;
|
|
@@ -55,4 +55,9 @@ export const InputValidation = css `
|
|
|
55
55
|
outline: 1px solid ${Colors.accent.red1};
|
|
56
56
|
}
|
|
57
57
|
`;
|
|
58
|
+
export const FILE_TYPE_ICON_MAP = {
|
|
59
|
+
"application/pdf": Icons.FilePdfIcon,
|
|
60
|
+
"image/png": Icons.FilePngIcon,
|
|
61
|
+
"image/jpeg": Icons.FileJpgIcon,
|
|
62
|
+
};
|
|
58
63
|
//# sourceMappingURL=shared.js.map
|
package/core/atoms/shared.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"shared.js","sourceRoot":"","sources":["../../../core/atoms/shared.tsx"],"names":[],"mappings":"AAAA,OAAO,MAAM,EAAE,EAAE,GAAG,EAAE,MAAM,mBAAmB,CAAC;AAChD,OAAO,EAAE,MAAM,EAAE,MAAM,gBAAgB,CAAC;
|
|
1
|
+
{"version":3,"file":"shared.js","sourceRoot":"","sources":["../../../core/atoms/shared.tsx"],"names":[],"mappings":"AAAA,OAAO,MAAM,EAAE,EAAE,GAAG,EAAE,MAAM,mBAAmB,CAAC;AAChD,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,gBAAgB,CAAC;AAE/C,MAAM,CAAC,MAAM,UAAU,GAAG,MAAM,CAAC,GAAG,CAKlC;;;;;;WAMS,CAAC,EAAE,MAAM,GAAG,MAAM,EAAE,EAAE,EAAE,CAAC,MAAM;;;;;;;;qBAQrB,CAAC,EAAE,UAAU,GAAG,KAAK,EAAE,EAAE,EAAE,CAC5C,UAAU,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,MAAM;;WAE1B,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC,UAAU,CAAC,SAAS,EAAE,EAAE,EAAE,CAAC,MAAM;sBACzC,CAAC,EACnB,UAAU,GAAG,KAAK,EAClB,gBAAgB,GAAG,MAAM,CAAC,IAAI,CAAC,YAAY,GAC5C,EAAE,EAAE,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,aAAa,CAAC,CAAC,CAAC,gBAAgB,CAAC;CACtD,CAAC;AAEF,MAAM,CAAC,MAAM,aAAa,GAAG,MAAM,CAAC,GAAG,CAAA;;;;CAItC,CAAC;AAEF,MAAM,CAAC,MAAM,eAAe,GAAG,GAAG,CAAA;;wBAEV,MAAM,CAAC,OAAO,CAAC,KAAK;wBACpB,MAAM,CAAC,OAAO,CAAC,KAAK;;;;;wBAKpB,MAAM,CAAC,IAAI,CAAC,KAAK;wBACjB,MAAM,CAAC,OAAO,CAAC,KAAK;;;;;wBAKpB,MAAM,CAAC,IAAI,CAAC,KAAK;wBACjB,MAAM,CAAC,MAAM,CAAC,KAAK;yBAClB,MAAM,CAAC,MAAM,CAAC,KAAK;;;;wBAIpB,MAAM,CAAC,IAAI,CAAC,KAAK;wBACjB,MAAM,CAAC,MAAM,CAAC,IAAI;;;;;wBAKlB,MAAM,CAAC,IAAI,CAAC,KAAK;wBACjB,MAAM,CAAC,MAAM,CAAC,IAAI;yBACjB,MAAM,CAAC,MAAM,CAAC,IAAI;;CAE1C,CAAC;AAEF,MAAM,CAAC,MAAM,kBAAkB,GAAuC;IACpE,iBAAiB,EAAE,KAAK,CAAC,WAAW;IACpC,WAAW,EAAE,KAAK,CAAC,WAAW;IAC9B,YAAY,EAAE,KAAK,CAAC,WAAW;CAChC,CAAC","sourcesContent":["import styled, { css } from \"styled-components\";\nimport { Colors, Icons } from \"../foundations\";\n\nexport const BaseButton = styled.div<{\n $underline?: boolean;\n $backgroundColor?: string;\n $color?: string;\n $width?: string;\n}>`\n display: flex;\n justify-content: center;\n align-items: center;\n gap: 10px;\n\n width: ${({ $width = \"auto\" }) => $width};\n\n padding: 10px 16px;\n border-radius: 4px;\n\n font-weight: 500;\n font-size: 14px;\n\n text-decoration: ${({ $underline = false }) =>\n $underline ? \"underline\" : \"none\"};\n\n color: ${({ $color = Colors.typography.whiteHigh }) => $color};\n background-color: ${({\n $underline = false,\n $backgroundColor = Colors.main.grantbiiBlue,\n }) => ($underline ? \"transparent\" : $backgroundColor)};\n`;\n\nexport const LabelledInput = styled.div`\n display: flex;\n align-items: center;\n gap: 8px;\n`;\n\nexport const InputValidation = css`\n &:disabled {\n background-color: ${Colors.neutral.grey4};\n border: 1px solid ${Colors.neutral.grey3};\n outline: none;\n }\n\n &:valid {\n background-color: ${Colors.base.white};\n border: 1px solid ${Colors.neutral.grey3};\n outline: none;\n }\n\n &:valid&:focus {\n background-color: ${Colors.base.white};\n border: 1px solid ${Colors.accent.blue1};\n outline: 1px solid ${Colors.accent.blue1};\n }\n\n &:invalid {\n background-color: ${Colors.base.white};\n border: 1px solid ${Colors.accent.red1};\n outline: none;\n }\n\n &:invalid&:focus {\n background-color: ${Colors.base.white};\n border: 1px solid ${Colors.accent.red1};\n outline: 1px solid ${Colors.accent.red1};\n }\n`;\n\nexport const FILE_TYPE_ICON_MAP: { [mimeType: string]: Icons.Icon } = {\n \"application/pdf\": Icons.FilePdfIcon,\n \"image/png\": Icons.FilePngIcon,\n \"image/jpeg\": Icons.FileJpgIcon,\n};\n"]}
|
|
@@ -4,13 +4,18 @@ import { useDropzone } from "react-dropzone";
|
|
|
4
4
|
import styled from "styled-components";
|
|
5
5
|
import { Badge } from "../atoms";
|
|
6
6
|
import { Colors, Icons, Responsive, Typography } from "../foundations";
|
|
7
|
+
import { FILE_TYPE_ICON_MAP } from "../atoms/shared";
|
|
7
8
|
const DEFAULT_MAX_FILE_SIZE_MB = 5;
|
|
8
9
|
const DEFAULT_MAX_FILES = 5;
|
|
9
10
|
const FileDrop = ({ uploadedFiles, uploadFiles, removeFile, errorMessage, maxFiles = DEFAULT_MAX_FILES, maxSizeMB = DEFAULT_MAX_FILE_SIZE_MB, }) => {
|
|
10
11
|
const reachedMaxUploads = uploadedFiles.length >= maxFiles;
|
|
11
12
|
const { getInputProps, getRootProps } = useDropzone({
|
|
12
13
|
onDrop: uploadFiles,
|
|
13
|
-
accept: {
|
|
14
|
+
accept: {
|
|
15
|
+
"application/pdf": [".pdf"],
|
|
16
|
+
"image/png": [".png"],
|
|
17
|
+
"image/jpeg": ["jpeg", ".jpg"],
|
|
18
|
+
},
|
|
14
19
|
disabled: reachedMaxUploads,
|
|
15
20
|
noClick: reachedMaxUploads,
|
|
16
21
|
noDrag: reachedMaxUploads,
|
|
@@ -37,7 +42,7 @@ const Dropzone = styled.div `
|
|
|
37
42
|
`;
|
|
38
43
|
const DropzoneContent = ({ maxFiles, maxSizeMB }) => (_jsxs(BaseDropzoneContent, { children: [_jsx(Icons.FileDashedIcon, { weight: "thin", size: 48, color: Colors.neutral.grey1 }), _jsxs(AllDropzoneText, { children: [_jsx(DropzoneText, { children: `Drop up to ${maxFiles} files here (${maxSizeMB}MB each)` }), _jsx(DropzoneSubtitle, { "$isHighlighted": true, children: DROPZONE_BROWSE_TEXT }), _jsx(DropzoneSubtitle, { children: FILE_FORMAT_TEXT })] })] }));
|
|
39
44
|
const DROPZONE_BROWSE_TEXT = "or click to browse with your file explorer";
|
|
40
|
-
const FILE_FORMAT_TEXT = "Accepted file formats:
|
|
45
|
+
const FILE_FORMAT_TEXT = "Accepted file formats: pdf, png, jpg";
|
|
41
46
|
const BaseDropzoneContent = styled.div `
|
|
42
47
|
display: flex;
|
|
43
48
|
flex-direction: column;
|
|
@@ -86,9 +91,6 @@ const BaseUploadedFiles = styled.div `
|
|
|
86
91
|
flex-direction: column;
|
|
87
92
|
gap: 4px;
|
|
88
93
|
`;
|
|
89
|
-
const FILE_TYPE_ICON_MAP = {
|
|
90
|
-
"application/pdf": Icons.FilePdfIcon,
|
|
91
|
-
};
|
|
92
94
|
export const useFileDrop = (initialFiles = [], maxFiles = DEFAULT_MAX_FILES, maxSizeMB = DEFAULT_MAX_FILE_SIZE_MB) => {
|
|
93
95
|
const [files, setFiles] = useState(() => initialFiles);
|
|
94
96
|
const [errorMessage, setErrorMessage] = useState();
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"FileDrop.js","sourceRoot":"","sources":["../../../core/molecules/FileDrop.tsx"],"names":[],"mappings":"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","sourcesContent":["import { useState } from \"react\";\nimport { useDropzone } from \"react-dropzone\";\nimport styled from \"styled-components\";\nimport { Badge } from \"../atoms\";\nimport { Colors, Icons, Responsive, Typography } from \"../foundations\";\n\nconst DEFAULT_MAX_FILE_SIZE_MB = 5;\nconst DEFAULT_MAX_FILES = 5;\n\ntype FileDropzoneProps = {\n uploadedFiles: File[];\n uploadFiles: (acceptedFiles: File[]) => void;\n removeFile: (fileName: string) => void;\n errorMessage?: string;\n maxFiles?: number;\n maxSizeMB?: number;\n};\n\nconst FileDrop = ({\n uploadedFiles,\n uploadFiles,\n removeFile,\n errorMessage,\n maxFiles = DEFAULT_MAX_FILES,\n maxSizeMB = DEFAULT_MAX_FILE_SIZE_MB,\n}: FileDropzoneProps) => {\n const reachedMaxUploads = uploadedFiles.length >= maxFiles;\n\n const { getInputProps, getRootProps } = useDropzone({\n onDrop: uploadFiles,\n accept: { \"application/pdf\": [\".pdf\"] },\n disabled: reachedMaxUploads,\n noClick: reachedMaxUploads,\n noDrag: reachedMaxUploads,\n multiple: true,\n });\n\n return (\n <BaseFileDrop>\n <Dropzone\n {...getRootProps()}\n $reachedMaxUploads={reachedMaxUploads}\n $hasError={!!errorMessage}\n >\n <input {...getInputProps()} type=\"file\" />\n <DropzoneContent maxFiles={maxFiles} maxSizeMB={maxSizeMB} />\n </Dropzone>\n\n {errorMessage ? <ErrorMessage>{errorMessage}</ErrorMessage> : <></>}\n\n <UploadedFiles uploadedFiles={uploadedFiles} removeFile={removeFile} />\n </BaseFileDrop>\n );\n};\n\nexport default FileDrop;\n\nconst BaseFileDrop = styled.div`\n width: 100%;\n display: flex;\n flex-direction: column;\n gap: 6px;\n`;\n\nconst Dropzone = styled.div<{\n $reachedMaxUploads: boolean;\n $hasError: boolean;\n}>`\n padding: 40px;\n border-radius: 6px;\n border: 1px solid\n ${({ $hasError }) =>\n $hasError ? Colors.accent.red1 : Colors.neutral.grey3};\n\n &:hover {\n cursor: ${({ $reachedMaxUploads }) =>\n $reachedMaxUploads ? \"not-allowed\" : \"pointer\"};\n }\n`;\n\ntype DropzoneContentProps = {\n maxFiles: number;\n maxSizeMB: number;\n};\n\nconst DropzoneContent = ({ maxFiles, maxSizeMB }: DropzoneContentProps) => (\n <BaseDropzoneContent>\n <Icons.FileDashedIcon\n weight=\"thin\"\n size={48}\n color={Colors.neutral.grey1}\n />\n <AllDropzoneText>\n <DropzoneText>\n {`Drop up to ${maxFiles} files here (${maxSizeMB}MB each)`}\n </DropzoneText>\n\n <DropzoneSubtitle $isHighlighted>{DROPZONE_BROWSE_TEXT}</DropzoneSubtitle>\n <DropzoneSubtitle>{FILE_FORMAT_TEXT}</DropzoneSubtitle>\n </AllDropzoneText>\n </BaseDropzoneContent>\n);\n\nconst DROPZONE_BROWSE_TEXT = \"or click to browse with your file explorer\";\nconst FILE_FORMAT_TEXT = \"Accepted file formats: .pdf (more coming soon)\";\n\nconst BaseDropzoneContent = styled.div`\n display: flex;\n flex-direction: column;\n gap: 24px;\n align-items: center;\n`;\n\nconst AllDropzoneText = styled.div`\n display: flex;\n flex-direction: column;\n gap: 4px;\n`;\n\nconst DropzoneText = styled.p`\n text-align: center;\n\n font-weight: 500;\n\n @media (width < ${Responsive.WIDTH_BREAKPOINTS.laptop}) {\n font-size: ${Typography.BODY_FONT_SIZES.small};\n }\n\n @media (width >= ${Responsive.WIDTH_BREAKPOINTS.laptop}) {\n font-size: ${Typography.BODY_FONT_SIZES.big};\n }\n`;\n\nconst DropzoneSubtitle = styled.p<{ $isHighlighted?: boolean }>`\n text-align: center;\n\n font-weight: 400;\n\n color: ${({ $isHighlighted = false }) =>\n $isHighlighted ? Colors.accent.yellow1 : Colors.typography.blackLow};\n\n @media (width < ${Responsive.WIDTH_BREAKPOINTS.laptop}) {\n font-size: ${Typography.HELPER_FONT_SIZES.small};\n }\n\n @media (width >= ${Responsive.WIDTH_BREAKPOINTS.laptop}) {\n font-size: ${Typography.HELPER_FONT_SIZES.big};\n }\n`;\n\nconst ErrorMessage = styled.p`\n color: ${Colors.accent.red1};\n`;\n\ntype UploadedFilesProps = {\n uploadedFiles: File[];\n removeFile: (fileName: string) => void;\n};\n\nconst UploadedFiles = ({ uploadedFiles, removeFile }: UploadedFilesProps) => (\n <BaseUploadedFiles>\n {uploadedFiles.map(({ name: fileName, type: fileType }) => (\n <Badge\n key={fileName}\n text={getFileNameWithoutExtension(fileName)}\n onClickClose={() => removeFile(fileName)}\n Icon={FILE_TYPE_ICON_MAP[fileType] ?? Icons.FileIcon}\n />\n ))}\n </BaseUploadedFiles>\n);\n\nconst BaseUploadedFiles = styled.div`\n display: flex;\n flex-direction: column;\n gap: 4px;\n`;\n\nconst FILE_TYPE_ICON_MAP: { [itemType: string]: Icons.Icon } = {\n \"application/pdf\": Icons.FilePdfIcon,\n};\n\nexport const useFileDrop = (\n initialFiles: File[] = [],\n maxFiles: number = DEFAULT_MAX_FILES,\n maxSizeMB: number = DEFAULT_MAX_FILE_SIZE_MB,\n) => {\n const [files, setFiles] = useState<File[]>(() => initialFiles);\n const [errorMessage, setErrorMessage] = useState<string | undefined>();\n\n const uploadFiles = (acceptedFiles: File[]) => {\n if (files.length + acceptedFiles.length > maxFiles) {\n setErrorMessage(() => `Maximum upload limit is ${maxFiles} files`);\n } else if (anyFileTooLarge(acceptedFiles, maxSizeMB)) {\n setErrorMessage(() => `Maximum file size is ${maxSizeMB}MB`);\n } else {\n setErrorMessage(() => undefined);\n setFiles((previousFiles) =>\n combineFilesWithoutDuplicates(previousFiles, acceptedFiles),\n );\n }\n };\n\n const removeFile = (fileName: string) => {\n setErrorMessage(() => undefined);\n setFiles((previousFiles) => filterFilesByName(previousFiles, fileName));\n };\n\n return {\n files,\n uploadFiles,\n removeFile,\n errorMessage,\n };\n};\n\nconst anyFileTooLarge = (files: File[], maxSizeMB: number): boolean =>\n files.some((file) => file.size > convertMegabytesToBytes(maxSizeMB));\n\nconst convertMegabytesToBytes = (megabytes: number): number =>\n megabytes * 1024 * 1024;\n\nconst combineFilesWithoutDuplicates = (\n oldFiles: File[],\n newFiles: File[],\n): File[] => {\n const newFileNames = newFiles.map((file) => file.name);\n const keptOldFiles = oldFiles.filter(\n (oldFile) => !newFileNames.includes(oldFile.name),\n );\n\n return [...keptOldFiles, ...newFiles];\n};\n\nconst filterFilesByName = (files: File[], fileName: string): File[] =>\n files.filter((file) => file.name !== fileName);\n\nconst getFileNameWithoutExtension = (fileName: string): string =>\n fileName.substring(0, fileName.lastIndexOf(\".\"));\n"]}
|
|
1
|
+
{"version":3,"file":"FileDrop.js","sourceRoot":"","sources":["../../../core/molecules/FileDrop.tsx"],"names":[],"mappings":"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","sourcesContent":["import { useState } from \"react\";\nimport { useDropzone } from \"react-dropzone\";\nimport styled from \"styled-components\";\nimport { Badge } from \"../atoms\";\nimport { Colors, Icons, Responsive, Typography } from \"../foundations\";\nimport { FILE_TYPE_ICON_MAP } from \"../atoms/shared\";\n\nconst DEFAULT_MAX_FILE_SIZE_MB = 5;\nconst DEFAULT_MAX_FILES = 5;\n\ntype FileDropzoneProps = {\n uploadedFiles: File[];\n uploadFiles: (acceptedFiles: File[]) => void;\n removeFile: (fileName: string) => void;\n errorMessage?: string;\n maxFiles?: number;\n maxSizeMB?: number;\n};\n\nconst FileDrop = ({\n uploadedFiles,\n uploadFiles,\n removeFile,\n errorMessage,\n maxFiles = DEFAULT_MAX_FILES,\n maxSizeMB = DEFAULT_MAX_FILE_SIZE_MB,\n}: FileDropzoneProps) => {\n const reachedMaxUploads = uploadedFiles.length >= maxFiles;\n\n const { getInputProps, getRootProps } = useDropzone({\n onDrop: uploadFiles,\n accept: {\n \"application/pdf\": [\".pdf\"],\n \"image/png\": [\".png\"],\n \"image/jpeg\": [\"jpeg\", \".jpg\"],\n },\n disabled: reachedMaxUploads,\n noClick: reachedMaxUploads,\n noDrag: reachedMaxUploads,\n multiple: true,\n });\n\n return (\n <BaseFileDrop>\n <Dropzone\n {...getRootProps()}\n $reachedMaxUploads={reachedMaxUploads}\n $hasError={!!errorMessage}\n >\n <input {...getInputProps()} type=\"file\" />\n <DropzoneContent maxFiles={maxFiles} maxSizeMB={maxSizeMB} />\n </Dropzone>\n\n {errorMessage ? <ErrorMessage>{errorMessage}</ErrorMessage> : <></>}\n\n <UploadedFiles uploadedFiles={uploadedFiles} removeFile={removeFile} />\n </BaseFileDrop>\n );\n};\n\nexport default FileDrop;\n\nconst BaseFileDrop = styled.div`\n width: 100%;\n display: flex;\n flex-direction: column;\n gap: 6px;\n`;\n\nconst Dropzone = styled.div<{\n $reachedMaxUploads: boolean;\n $hasError: boolean;\n}>`\n padding: 40px;\n border-radius: 6px;\n border: 1px solid\n ${({ $hasError }) =>\n $hasError ? Colors.accent.red1 : Colors.neutral.grey3};\n\n &:hover {\n cursor: ${({ $reachedMaxUploads }) =>\n $reachedMaxUploads ? \"not-allowed\" : \"pointer\"};\n }\n`;\n\ntype DropzoneContentProps = {\n maxFiles: number;\n maxSizeMB: number;\n};\n\nconst DropzoneContent = ({ maxFiles, maxSizeMB }: DropzoneContentProps) => (\n <BaseDropzoneContent>\n <Icons.FileDashedIcon\n weight=\"thin\"\n size={48}\n color={Colors.neutral.grey1}\n />\n <AllDropzoneText>\n <DropzoneText>\n {`Drop up to ${maxFiles} files here (${maxSizeMB}MB each)`}\n </DropzoneText>\n\n <DropzoneSubtitle $isHighlighted>{DROPZONE_BROWSE_TEXT}</DropzoneSubtitle>\n <DropzoneSubtitle>{FILE_FORMAT_TEXT}</DropzoneSubtitle>\n </AllDropzoneText>\n </BaseDropzoneContent>\n);\n\nconst DROPZONE_BROWSE_TEXT = \"or click to browse with your file explorer\";\nconst FILE_FORMAT_TEXT = \"Accepted file formats: pdf, png, jpg\";\n\nconst BaseDropzoneContent = styled.div`\n display: flex;\n flex-direction: column;\n gap: 24px;\n align-items: center;\n`;\n\nconst AllDropzoneText = styled.div`\n display: flex;\n flex-direction: column;\n gap: 4px;\n`;\n\nconst DropzoneText = styled.p`\n text-align: center;\n\n font-weight: 500;\n\n @media (width < ${Responsive.WIDTH_BREAKPOINTS.laptop}) {\n font-size: ${Typography.BODY_FONT_SIZES.small};\n }\n\n @media (width >= ${Responsive.WIDTH_BREAKPOINTS.laptop}) {\n font-size: ${Typography.BODY_FONT_SIZES.big};\n }\n`;\n\nconst DropzoneSubtitle = styled.p<{ $isHighlighted?: boolean }>`\n text-align: center;\n\n font-weight: 400;\n\n color: ${({ $isHighlighted = false }) =>\n $isHighlighted ? Colors.accent.yellow1 : Colors.typography.blackLow};\n\n @media (width < ${Responsive.WIDTH_BREAKPOINTS.laptop}) {\n font-size: ${Typography.HELPER_FONT_SIZES.small};\n }\n\n @media (width >= ${Responsive.WIDTH_BREAKPOINTS.laptop}) {\n font-size: ${Typography.HELPER_FONT_SIZES.big};\n }\n`;\n\nconst ErrorMessage = styled.p`\n color: ${Colors.accent.red1};\n`;\n\ntype UploadedFilesProps = {\n uploadedFiles: File[];\n removeFile: (fileName: string) => void;\n};\n\nconst UploadedFiles = ({ uploadedFiles, removeFile }: UploadedFilesProps) => (\n <BaseUploadedFiles>\n {uploadedFiles.map(({ name: fileName, type: fileType }) => (\n <Badge\n key={fileName}\n text={getFileNameWithoutExtension(fileName)}\n onClickClose={() => removeFile(fileName)}\n Icon={FILE_TYPE_ICON_MAP[fileType] ?? Icons.FileIcon}\n />\n ))}\n </BaseUploadedFiles>\n);\n\nconst BaseUploadedFiles = styled.div`\n display: flex;\n flex-direction: column;\n gap: 4px;\n`;\n\nexport const useFileDrop = (\n initialFiles: File[] = [],\n maxFiles: number = DEFAULT_MAX_FILES,\n maxSizeMB: number = DEFAULT_MAX_FILE_SIZE_MB,\n) => {\n const [files, setFiles] = useState<File[]>(() => initialFiles);\n const [errorMessage, setErrorMessage] = useState<string | undefined>();\n\n const uploadFiles = (acceptedFiles: File[]) => {\n if (files.length + acceptedFiles.length > maxFiles) {\n setErrorMessage(() => `Maximum upload limit is ${maxFiles} files`);\n } else if (anyFileTooLarge(acceptedFiles, maxSizeMB)) {\n setErrorMessage(() => `Maximum file size is ${maxSizeMB}MB`);\n } else {\n setErrorMessage(() => undefined);\n setFiles((previousFiles) =>\n combineFilesWithoutDuplicates(previousFiles, acceptedFiles),\n );\n }\n };\n\n const removeFile = (fileName: string) => {\n setErrorMessage(() => undefined);\n setFiles((previousFiles) => filterFilesByName(previousFiles, fileName));\n };\n\n return {\n files,\n uploadFiles,\n removeFile,\n errorMessage,\n };\n};\n\nconst anyFileTooLarge = (files: File[], maxSizeMB: number): boolean =>\n files.some((file) => file.size > convertMegabytesToBytes(maxSizeMB));\n\nconst convertMegabytesToBytes = (megabytes: number): number =>\n megabytes * 1024 * 1024;\n\nconst combineFilesWithoutDuplicates = (\n oldFiles: File[],\n newFiles: File[],\n): File[] => {\n const newFileNames = newFiles.map((file) => file.name);\n const keptOldFiles = oldFiles.filter(\n (oldFile) => !newFileNames.includes(oldFile.name),\n );\n\n return [...keptOldFiles, ...newFiles];\n};\n\nconst filterFilesByName = (files: File[], fileName: string): File[] =>\n files.filter((file) => file.name !== fileName);\n\nconst getFileNameWithoutExtension = (fileName: string): string =>\n fileName.substring(0, fileName.lastIndexOf(\".\"));\n"]}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
2
|
import styled from "styled-components";
|
|
3
3
|
import { Badge, Button } from "../../atoms";
|
|
4
|
+
import { FILE_TYPE_ICON_MAP } from "../../atoms/shared";
|
|
4
5
|
import { Colors, Icons } from "../../foundations";
|
|
5
6
|
import { useGrantMatchContext } from "./context";
|
|
6
7
|
const ActiveQueryFiles = () => (_jsxs(BaseActiveFiles, { children: [_jsx(FileBadges, {}), _jsx(ResetFilesButton, {})] }));
|
|
@@ -39,9 +40,6 @@ const BaseFileBadges = styled.div `
|
|
|
39
40
|
|
|
40
41
|
/* TODO: fade effect on overflow-x */
|
|
41
42
|
`;
|
|
42
|
-
const FILE_TYPE_ICON_MAP = {
|
|
43
|
-
"application/pdf": Icons.FilePdfIcon,
|
|
44
|
-
};
|
|
45
43
|
const ResetFilesButton = () => {
|
|
46
44
|
const { activeQuery, updateActiveQuery } = useGrantMatchContext();
|
|
47
45
|
return (_jsx(Button, { text: "Reset", onClick: () => updateActiveQuery({ files: [], text: activeQuery.text }), color: Colors.typography.blackMedium, underline: true }));
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ActiveQueryFiles.js","sourceRoot":"","sources":["../../../../core/organisms/GrantMatch/ActiveQueryFiles.tsx"],"names":[],"mappings":";
|
|
1
|
+
{"version":3,"file":"ActiveQueryFiles.js","sourceRoot":"","sources":["../../../../core/organisms/GrantMatch/ActiveQueryFiles.tsx"],"names":[],"mappings":";AAAA,OAAO,MAAM,MAAM,mBAAmB,CAAC;AACvC,OAAO,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAC5C,OAAO,EAAE,kBAAkB,EAAE,MAAM,oBAAoB,CAAC;AACxD,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,mBAAmB,CAAC;AAClD,OAAO,EAAE,oBAAoB,EAAE,MAAM,WAAW,CAAC;AAEjD,MAAM,gBAAgB,GAAG,GAAG,EAAE,CAAC,CAC7B,MAAC,eAAe,eACd,KAAC,UAAU,KAAG,EACd,KAAC,gBAAgB,KAAG,IACJ,CACnB,CAAC;AAEF,eAAe,gBAAgB,CAAC;AAEhC,MAAM,eAAe,GAAG,MAAM,CAAC,GAAG,CAAA;;;;CAIjC,CAAC;AAEF,MAAM,UAAU,GAAG,GAAG,EAAE;IACtB,MAAM,EAAE,WAAW,EAAE,iBAAiB,EAAE,GAAG,oBAAoB,EAAE,CAAC;IAElE,MAAM,qBAAqB,GAAG,CAAC,QAAgB,EAAE,EAAE;QACjD,MAAM,QAAQ,GAAG;YACf,KAAK,EAAE,WAAW,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,IAAI,KAAK,QAAQ,CAAC;YACjE,IAAI,EAAE,WAAW,CAAC,IAAI;SACvB,CAAC;QAEF,iBAAiB,CAAC,QAAQ,CAAC,CAAC;IAC9B,CAAC,CAAC;IAEF,OAAO,CACL,KAAC,cAAc,cACZ,WAAW,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CAC/B,KAAC,KAAK,IAEJ,IAAI,EAAE,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,EAAE,IAAI,CAAC,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC,EACxD,IAAI,EAAE,kBAAkB,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,KAAK,CAAC,QAAQ,EACrD,YAAY,EAAE,GAAG,EAAE,CAAC,qBAAqB,CAAC,IAAI,CAAC,IAAI,CAAC,EACpD,eAAe,EAAE,GAAG,IAJf,IAAI,CAAC,IAAI,CAKd,CACH,CAAC,GACa,CAClB,CAAC;AACJ,CAAC,CAAC;AAEF,MAAM,cAAc,GAAG,MAAM,CAAC,GAAG,CAAA;;;;;;;;;;;;;;;;;CAiBhC,CAAC;AAEF,MAAM,gBAAgB,GAAG,GAAG,EAAE;IAC5B,MAAM,EAAE,WAAW,EAAE,iBAAiB,EAAE,GAAG,oBAAoB,EAAE,CAAC;IAElE,OAAO,CACL,KAAC,MAAM,IACL,IAAI,EAAC,OAAO,EACZ,OAAO,EAAE,GAAG,EAAE,CAAC,iBAAiB,CAAC,EAAE,KAAK,EAAE,EAAE,EAAE,IAAI,EAAE,WAAW,CAAC,IAAI,EAAE,CAAC,EACvE,KAAK,EAAE,MAAM,CAAC,UAAU,CAAC,WAAW,EACpC,SAAS,SACT,CACH,CAAC;AACJ,CAAC,CAAC","sourcesContent":["import styled from \"styled-components\";\nimport { Badge, Button } from \"../../atoms\";\nimport { FILE_TYPE_ICON_MAP } from \"../../atoms/shared\";\nimport { Colors, Icons } from \"../../foundations\";\nimport { useGrantMatchContext } from \"./context\";\n\nconst ActiveQueryFiles = () => (\n <BaseActiveFiles>\n <FileBadges />\n <ResetFilesButton />\n </BaseActiveFiles>\n);\n\nexport default ActiveQueryFiles;\n\nconst BaseActiveFiles = styled.div`\n display: flex;\n align-items: center;\n justify-content: space-between;\n`;\n\nconst FileBadges = () => {\n const { activeQuery, updateActiveQuery } = useGrantMatchContext();\n\n const removeActiveQueryFile = (fileName: string) => {\n const newQuery = {\n files: activeQuery.files.filter((file) => file.name !== fileName),\n text: activeQuery.text,\n };\n\n updateActiveQuery(newQuery);\n };\n\n return (\n <BaseFileBadges>\n {activeQuery.files.map((file) => (\n <Badge\n key={file.name}\n text={file.name.substring(0, file.name.lastIndexOf(\".\"))}\n Icon={FILE_TYPE_ICON_MAP[file.type] ?? Icons.FileIcon}\n onClickClose={() => removeActiveQueryFile(file.name)}\n textWidthPixels={160}\n />\n ))}\n </BaseFileBadges>\n );\n};\n\nconst BaseFileBadges = styled.div`\n display: flex;\n align-items: center;\n gap: 8px;\n\n width: 100%;\n\n overflow-x: auto;\n\n /* hide scrollbar but still allow for scrolling */\n -ms-overflow-style: none;\n scrollbar-width: none;\n ::-webkit-scrollbar {\n display: none;\n }\n\n /* TODO: fade effect on overflow-x */\n`;\n\nconst ResetFilesButton = () => {\n const { activeQuery, updateActiveQuery } = useGrantMatchContext();\n\n return (\n <Button\n text=\"Reset\"\n onClick={() => updateActiveQuery({ files: [], text: activeQuery.text })}\n color={Colors.typography.blackMedium}\n underline\n />\n );\n};\n"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@grantbii/design-system",
|
|
3
|
-
"version": "1.3.
|
|
3
|
+
"version": "1.3.1",
|
|
4
4
|
"description": "Grantbii's Design System",
|
|
5
5
|
"homepage": "https://design.grantbii.com",
|
|
6
6
|
"repository": {
|
|
@@ -19,7 +19,7 @@
|
|
|
19
19
|
"build-storybook": "storybook build"
|
|
20
20
|
},
|
|
21
21
|
"dependencies": {
|
|
22
|
-
"@grantbii/ui-core": "1.
|
|
22
|
+
"@grantbii/ui-core": "1.1.0",
|
|
23
23
|
"@phosphor-icons/react": "2.1.10",
|
|
24
24
|
"country-flag-icons": "1.5.20",
|
|
25
25
|
"next": "15.5.3",
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { Input, mapEnumToOptions } from "@/.";
|
|
2
|
-
import {
|
|
2
|
+
import { CostItem } from "@grantbii/ui-core/grant/enums";
|
|
3
3
|
const meta = {
|
|
4
4
|
title: "Atoms/Input",
|
|
5
5
|
component: Input,
|
|
@@ -25,7 +25,7 @@ export const WithDatalist = {
|
|
|
25
25
|
args: {
|
|
26
26
|
placeholder: "Enter a cost item",
|
|
27
27
|
datalistId: "supportable-cost-items",
|
|
28
|
-
datalistOptions: mapEnumToOptions(
|
|
28
|
+
datalistOptions: mapEnumToOptions(CostItem),
|
|
29
29
|
},
|
|
30
30
|
};
|
|
31
31
|
//# sourceMappingURL=Input.stories.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Input.stories.js","sourceRoot":"","sources":["../../../stories/atoms/Input.stories.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,gBAAgB,EAAE,MAAM,KAAK,CAAC;AAC9C,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"Input.stories.js","sourceRoot":"","sources":["../../../stories/atoms/Input.stories.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,gBAAgB,EAAE,MAAM,KAAK,CAAC;AAC9C,OAAO,EAAE,QAAQ,EAAE,MAAM,+BAA+B,CAAC;AAGzD,MAAM,IAAI,GAAuB;IAC/B,KAAK,EAAE,aAAa;IACpB,SAAS,EAAE,KAAK;IAChB,IAAI,EAAE,CAAC,UAAU,CAAC;IAClB,UAAU,EAAE;QACV,MAAM,EAAE,UAAU;KACnB;CACF,CAAC;AAEF,eAAe,IAAI,CAAC;AAIpB,MAAM,CAAC,MAAM,UAAU,GAAU;IAC/B,IAAI,EAAE,EAAE,WAAW,EAAE,WAAW,EAAE;CACnC,CAAC;AAEF,MAAM,CAAC,MAAM,cAAc,GAAU;IACnC,IAAI,EAAE,EAAE,WAAW,EAAE,cAAc,EAAE,IAAI,EAAE,QAAQ,EAAE;CACtD,CAAC;AAEF,MAAM,CAAC,MAAM,UAAU,GAAU;IAC/B,IAAI,EAAE,EAAE,WAAW,EAAE,kBAAkB,EAAE,IAAI,EAAE,OAAO,EAAE;CACzD,CAAC;AAEF,MAAM,CAAC,MAAM,aAAa,GAAU;IAClC,IAAI,EAAE,EAAE,WAAW,EAAE,wBAAwB,EAAE,SAAS,EAAE,EAAE,EAAE;CAC/D,CAAC;AAEF,MAAM,CAAC,MAAM,YAAY,GAAU;IACjC,IAAI,EAAE;QACJ,WAAW,EAAE,mBAAmB;QAChC,UAAU,EAAE,wBAAwB;QACpC,eAAe,EAAE,gBAAgB,CAAC,QAAQ,CAAC;KAC5C;CACF,CAAC","sourcesContent":["import { Input, mapEnumToOptions } from \"@/.\";\nimport { CostItem } from \"@grantbii/ui-core/grant/enums\";\nimport type { Meta, StoryObj } from \"@storybook/nextjs-vite\";\n\nconst meta: Meta<typeof Input> = {\n title: \"Atoms/Input\",\n component: Input,\n tags: [\"autodocs\"],\n parameters: {\n layout: \"centered\",\n },\n};\n\nexport default meta;\n\ntype Story = StoryObj<typeof meta>;\n\nexport const BasicInput: Story = {\n args: { placeholder: \"Type here\" },\n};\n\nexport const NumericalField: Story = {\n args: { placeholder: \"Numbers only\", type: \"number\" },\n};\n\nexport const EmailField: Story = {\n args: { placeholder: \"Enter your email\", type: \"email\" },\n};\n\nexport const MinimumLength: Story = {\n args: { placeholder: \"At least 10 characters\", minLength: 10 },\n};\n\nexport const WithDatalist: Story = {\n args: {\n placeholder: \"Enter a cost item\",\n datalistId: \"supportable-cost-items\",\n datalistOptions: mapEnumToOptions(CostItem),\n },\n};\n"]}
|