@grantbii/design-system 1.0.66 → 1.0.68

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/README.md CHANGED
@@ -1,5 +1,8 @@
1
1
  # Grantbii's Design System
2
2
 
3
+ Storybook's viewport triggers media query for small screen (e.g. mobile) by default.
4
+ View in full screen to see components for big screen (e.g. desktop).
5
+
3
6
  Based on Grantbii's Global Design Library in Figma.
4
7
 
5
8
  Approach: Atomic Design
@@ -1,8 +1,6 @@
1
1
  type BrandLogoProps = {
2
- width?: number;
3
- height?: number;
4
2
  isDarkTheme?: boolean;
5
3
  alt?: string;
6
4
  };
7
- declare const BrandLogo: ({ width, height, isDarkTheme, alt, }: BrandLogoProps) => import("react/jsx-runtime").JSX.Element;
5
+ declare const BrandLogo: ({ isDarkTheme, alt, }: BrandLogoProps) => import("react/jsx-runtime").JSX.Element;
8
6
  export default BrandLogo;
@@ -3,5 +3,18 @@ import { jsx as _jsx } from "react/jsx-runtime";
3
3
  import Image from "next/image";
4
4
  import darkLogo from "../assets/logos/brand_logo-dark.webp";
5
5
  import lightLogo from "../assets/logos/brand_logo-light.webp";
6
- const BrandLogo = ({ width = 250, height = 80, isDarkTheme = true, alt = "Grantbii", }) => (_jsx(Image, { src: isDarkTheme ? darkLogo : lightLogo, alt: alt, width: width, height: height, priority: true }));
6
+ import styled from "styled-components";
7
+ import { Responsive } from "../foundations";
8
+ const BrandLogo = ({ isDarkTheme = true, alt = "Grantbii", }) => (_jsx(CustomImage, { src: isDarkTheme ? darkLogo : lightLogo, alt: alt, priority: true }));
7
9
  export default BrandLogo;
10
+ const CustomImage = styled(Image) `
11
+ @media (width < ${Responsive.WIDTH_BREAKPOINTS.laptop}) {
12
+ width: 125px;
13
+ height: 40px;
14
+ }
15
+
16
+ @media (width >= ${Responsive.WIDTH_BREAKPOINTS.laptop}) {
17
+ width: 150px;
18
+ height: 48px;
19
+ }
20
+ `;
@@ -1,5 +1 @@
1
1
  export * from "@phosphor-icons/react";
2
- type GrantMatchIconProps = {
3
- size?: number;
4
- };
5
- export declare const GrantMatchIcon: ({ size }: GrantMatchIconProps) => import("react/jsx-runtime").JSX.Element;
@@ -1,5 +1 @@
1
- import { jsx as _jsx } from "react/jsx-runtime";
2
1
  export * from "@phosphor-icons/react";
3
- import Image from "next/image";
4
- import grantMatchIcon from "../assets/icons/grant_match.webp";
5
- export const GrantMatchIcon = ({ size = 20 }) => (_jsx(Image, { src: grantMatchIcon, alt: "Grant Match", width: size, height: size }));
@@ -1,4 +1,4 @@
1
- export * as Breakpoints from "./breakpoints";
1
+ export * as Responsive from "./responsive";
2
2
  export * as Colors from "./colors";
3
3
  export * as Flags from "./flags";
4
4
  export * as Icons from "./icons";
@@ -1,4 +1,4 @@
1
- export * as Breakpoints from "./breakpoints";
1
+ export * as Responsive from "./responsive";
2
2
  export * as Colors from "./colors";
3
3
  export * as Flags from "./flags";
4
4
  export * as Icons from "./icons";
@@ -0,0 +1,3 @@
1
+ export declare const WIDTH_BREAKPOINTS: {
2
+ laptop: string;
3
+ };
@@ -0,0 +1,3 @@
1
+ export const WIDTH_BREAKPOINTS = {
2
+ laptop: "1024px",
3
+ };
@@ -1,3 +1,4 @@
1
+ export type ScreenSize = "big" | "small";
1
2
  export type Option = {
2
3
  label: string;
3
4
  value: string;
@@ -1,14 +1,10 @@
1
- export declare const FONT_SIZE_PIXELS_DESKTOP: {
2
- title: string;
3
- header: string;
4
- subheader: string;
5
- body: string;
6
- helper: string;
7
- };
8
- export declare const FONT_SIZE_PIXELS_MOBILE: {
9
- title: string;
10
- header: string;
11
- subheader: string;
12
- body: string;
13
- helper: string;
1
+ import { ScreenSize } from "./types";
2
+ type FontSizes = {
3
+ [screenSize in ScreenSize]: string;
14
4
  };
5
+ export declare const TITLE_FONT_SIZES: FontSizes;
6
+ export declare const HEADER_FONT_SIZES: FontSizes;
7
+ export declare const SUBHEADER_FONT_SIZES: FontSizes;
8
+ export declare const BODY_FONT_SIZES: FontSizes;
9
+ export declare const HELPER_FONT_SIZES: FontSizes;
10
+ export {};
@@ -1,14 +1,20 @@
1
- export const FONT_SIZE_PIXELS_DESKTOP = {
2
- title: "24px",
3
- header: "22px",
4
- subheader: "20px",
5
- body: "16px",
6
- helper: "14px",
7
- };
8
- export const FONT_SIZE_PIXELS_MOBILE = {
9
- title: "22px",
10
- header: "20px",
11
- subheader: "18px",
12
- body: "14px",
13
- helper: "12px",
1
+ export const TITLE_FONT_SIZES = {
2
+ big: "24px",
3
+ small: "22px",
4
+ };
5
+ export const HEADER_FONT_SIZES = {
6
+ big: "22px",
7
+ small: "20px",
8
+ };
9
+ export const SUBHEADER_FONT_SIZES = {
10
+ big: "20px",
11
+ small: "18px",
12
+ };
13
+ export const BODY_FONT_SIZES = {
14
+ big: "16px",
15
+ small: "14px",
16
+ };
17
+ export const HELPER_FONT_SIZES = {
18
+ big: "14px",
19
+ small: "12px",
14
20
  };
@@ -4,7 +4,7 @@ import { useState } from "react";
4
4
  import { useDropzone } from "react-dropzone";
5
5
  import styled from "styled-components";
6
6
  import { Badge } from "../atoms";
7
- import { Colors, Icons } from "../foundations";
7
+ import { Colors, Icons, Responsive, Typography } from "../foundations";
8
8
  const DEFAULT_MAX_FILE_SIZE_MB = 5;
9
9
  const DEFAULT_MAX_FILES = 5;
10
10
  const FileDrop = ({ uploadedFiles, uploadFiles, removeFile, errorMessage, maxFiles = DEFAULT_MAX_FILES, maxSizeMB = DEFAULT_MAX_FILE_SIZE_MB, }) => {
@@ -36,36 +36,47 @@ const Dropzone = styled.div `
36
36
  cursor: ${({ $reachedMaxUploads }) => $reachedMaxUploads ? "not-allowed" : "pointer"};
37
37
  }
38
38
  `;
39
- const DropzoneContent = ({ maxFiles, maxSizeMB }) => (_jsxs(BaseDropzoneContent, { children: [_jsx(Icons.FileDashedIcon, { weight: "thin", size: 48, color: Colors.neutral.grey1 }), _jsxs(DropzoneText, { children: [_jsx(DropzoneTitle, { children: `Drop up to ${maxFiles} files here ( ${maxSizeMB}MB each)` }), _jsx(DropzoneHighlightedSubtitle, { children: DROPZONE_BROWSE_TEXT }), _jsx(DropzoneSubtitle, { children: FILE_FORMAT_TEXT })] })] }));
39
+ 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 })] })] }));
40
40
  const DROPZONE_BROWSE_TEXT = "or click to browse with your file explorer";
41
- const FILE_FORMAT_TEXT = "Accepted file formats: .pdf (Coming soon: .doc, .ppt, .csv)";
41
+ const FILE_FORMAT_TEXT = "Accepted file formats: .pdf (more coming soon)";
42
42
  const BaseDropzoneContent = styled.div `
43
43
  display: flex;
44
44
  flex-direction: column;
45
45
  gap: 24px;
46
46
  align-items: center;
47
47
  `;
48
- const DropzoneText = styled.div `
48
+ const AllDropzoneText = styled.div `
49
49
  display: flex;
50
50
  flex-direction: column;
51
51
  gap: 4px;
52
52
  `;
53
- const DropzoneTitle = styled.h3 `
54
- font-weight: 500;
55
- font-size: 14px;
53
+ const DropzoneText = styled.p `
56
54
  text-align: center;
57
- `;
58
- const DropzoneHighlightedSubtitle = styled.p `
59
- font-weight: 400;
60
- font-size: 12px;
61
- text-align: center;
62
- color: ${Colors.accent.yellow1};
55
+
56
+ font-weight: 500;
57
+
58
+ @media (width < ${Responsive.WIDTH_BREAKPOINTS.laptop}) {
59
+ font-size: ${Typography.BODY_FONT_SIZES.small};
60
+ }
61
+
62
+ @media (width >= ${Responsive.WIDTH_BREAKPOINTS.laptop}) {
63
+ font-size: ${Typography.BODY_FONT_SIZES.big};
64
+ }
63
65
  `;
64
66
  const DropzoneSubtitle = styled.p `
65
- font-weight: 400;
66
- font-size: 12px;
67
67
  text-align: center;
68
- color: ${Colors.typography.blackLow};
68
+
69
+ font-weight: 400;
70
+
71
+ color: ${({ $isHighlighted = false }) => $isHighlighted ? Colors.accent.yellow1 : Colors.typography.blackLow};
72
+
73
+ @media (width < ${Responsive.WIDTH_BREAKPOINTS.laptop}) {
74
+ font-size: ${Typography.HELPER_FONT_SIZES.small};
75
+ }
76
+
77
+ @media (width >= ${Responsive.WIDTH_BREAKPOINTS.laptop}) {
78
+ font-size: ${Typography.HELPER_FONT_SIZES.big};
79
+ }
69
80
  `;
70
81
  const ErrorMessage = styled.p `
71
82
  color: ${Colors.accent.red1};
@@ -5,10 +5,9 @@ type ModalProps = {
5
5
  footer?: ReactNode;
6
6
  width?: string;
7
7
  height?: string;
8
- isFullScreen?: boolean;
9
8
  onClickCancel: MouseEventHandler<HTMLButtonElement>;
10
9
  };
11
- declare const Modal: ({ header, content, footer, width, height, isFullScreen, onClickCancel, }: ModalProps) => import("react/jsx-runtime").JSX.Element;
10
+ declare const Modal: ({ header, content, footer, width, height, onClickCancel, }: ModalProps) => import("react/jsx-runtime").JSX.Element;
12
11
  export default Modal;
13
12
  export declare const useModal: () => {
14
13
  showModal: boolean;
@@ -1,10 +1,10 @@
1
1
  "use client";
2
2
  import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
3
3
  import { useCallback, useState } from "react";
4
- import styled, { css } from "styled-components";
4
+ import styled from "styled-components";
5
5
  import { Button } from "../atoms";
6
- import { Colors } from "../foundations";
7
- const Modal = ({ header, content, footer, width, height, isFullScreen, onClickCancel, }) => (_jsx(Overlay, { "$isFullScreen": isFullScreen, children: _jsxs(ModalWindow, { "$isFullScreen": isFullScreen, "$width": width, "$height": height, children: [header ? _jsx(ModalHeader, { children: header }) : _jsx(_Fragment, {}), _jsx(ModalBody, { children: content }), _jsxs(ModalFooter, { children: [_jsx(CancelButton, { onClick: onClickCancel }), footer ? footer : _jsx(_Fragment, {})] })] }) }));
6
+ import { Colors, Responsive } from "../foundations";
7
+ const Modal = ({ header, content, footer, width, height, onClickCancel, }) => (_jsx(Overlay, { children: _jsxs(ModalWindow, { "$width": width, "$height": height, children: [header ? _jsx(ModalHeader, { children: header }) : _jsx(_Fragment, {}), _jsx(ModalBody, { children: content }), _jsxs(ModalFooter, { children: [_jsx(CancelButton, { onClick: onClickCancel }), footer ? footer : _jsx(_Fragment, {})] })] }) }));
8
8
  export default Modal;
9
9
  export const useModal = () => {
10
10
  const [showModal, setShowModal] = useState(false);
@@ -31,7 +31,7 @@ export const useModal = () => {
31
31
  const Overlay = styled.div `
32
32
  background-color: ${Colors.semantic.overlay};
33
33
 
34
- z-index: ${({ $isFullScreen }) => $isFullScreen ? Number.MAX_SAFE_INTEGER - 1 : Number.MAX_SAFE_INTEGER};
34
+ z-index: ${Number.MAX_SAFE_INTEGER};
35
35
  position: fixed;
36
36
  top: 0px;
37
37
  left: 0px;
@@ -49,21 +49,31 @@ const ModalWindow = styled.div `
49
49
  flex-direction: column;
50
50
 
51
51
  background-color: ${Colors.base.white};
52
- border-radius: ${({ $isFullScreen }) => ($isFullScreen ? 0 : 6)}px;
53
-
54
- width: ${({ $isFullScreen, $width = "auto" }) => $isFullScreen ? "100%" : $width};
55
- height: ${({ $isFullScreen, $height = "auto" }) => $isFullScreen ? "100%" : $height};
56
52
 
57
53
  min-height: 100px;
58
54
  max-height: 100vh;
59
55
 
60
- ${({ $isFullScreen = false }) => $isFullScreen
61
- ? css `
62
- position: fixed;
63
- bottom: 0px;
64
- left: 0px;
65
- `
66
- : ""}
56
+ @media (width < ${Responsive.WIDTH_BREAKPOINTS.laptop}) {
57
+ position: fixed;
58
+ bottom: 0px;
59
+ left: 0px;
60
+
61
+ width: 100%;
62
+ height: 100%;
63
+
64
+ border-radius: 0px;
65
+ }
66
+
67
+ @media (width >= ${Responsive.WIDTH_BREAKPOINTS.laptop}) {
68
+ position: static;
69
+ bottom: auto;
70
+ left: auto;
71
+
72
+ width: ${({ $width }) => $width};
73
+ height: ${({ $height }) => $height};
74
+
75
+ border-radius: 6px;
76
+ }
67
77
  `;
68
78
  const ModalHeader = styled.div `
69
79
  font-weight: 500;
@@ -1,14 +1,12 @@
1
+ import { GrantFilters } from "@grantbii/ui-base/grant/models";
1
2
  import { GrantMatchQuery } from "@grantbii/ui-base/match/models";
2
- type GrantMatchProps = GrantMatchQueryProps & {
3
- isSmallerThanLaptop?: boolean;
3
+ type GrantMatchProps = {
4
+ activeQuery: GrantMatchQuery;
5
+ updateActiveQuery: (newQuery: GrantMatchQuery) => void;
6
+ removeActiveQueryFile: (fileName: string) => void;
7
+ removeActiveQueryText: () => void;
8
+ resetActiveQuery: () => void;
4
9
  };
5
- declare const GrantMatch: ({ query, updateQuery, removeQueryFile, removeQueryText, resetQuery, isSmallerThanLaptop, }: GrantMatchProps) => import("react/jsx-runtime").JSX.Element;
10
+ declare const GrantMatch: ({ activeQuery, updateActiveQuery, removeActiveQueryFile, removeActiveQueryText, resetActiveQuery, }: GrantMatchProps) => import("react/jsx-runtime").JSX.Element;
6
11
  export default GrantMatch;
7
- type GrantMatchQueryProps = {
8
- query: GrantMatchQuery;
9
- updateQuery: (newQuery: GrantMatchQuery) => void;
10
- removeQueryFile: (fileName: string) => void;
11
- removeQueryText: () => void;
12
- resetQuery: () => void;
13
- };
14
- export declare const useGrantMatchQueryItems: (performGrantMatch: (newQuery: GrantMatchQuery) => void, resetGrantMatch: () => void) => GrantMatchQueryProps;
12
+ export declare const useGrantMatchActiveQuery: (filters: GrantFilters, performGrantMatch: (newQuery: GrantMatchQuery, filters: GrantFilters) => void, resetGrantMatch: () => void) => GrantMatchProps;
@@ -1,65 +1,53 @@
1
1
  "use client";
2
- import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
3
3
  import { isGrantMatchActive } from "@grantbii/ui-base/match/mappings";
4
4
  import { useState } from "react";
5
5
  import styled from "styled-components";
6
6
  import { Badge, Button, Textarea } from "../atoms";
7
- import { Colors, Icons } from "../foundations";
7
+ import { Colors, Icons, Responsive, Typography } from "../foundations";
8
8
  import { FileDrop, Modal, useFileDrop, useModal } from "../molecules";
9
- const GrantMatch = ({ query, updateQuery, removeQueryFile, removeQueryText, resetQuery, isSmallerThanLaptop, }) => {
9
+ const GrantMatch = ({ activeQuery, updateActiveQuery, removeActiveQueryFile, removeActiveQueryText, resetActiveQuery, }) => {
10
10
  const { showModal, openModal, closeModal } = useModal();
11
- const isActive = isGrantMatchActive(query);
12
- const updateActiveQuery = (newQuery) => {
13
- updateQuery(newQuery);
14
- closeModal();
11
+ const [queryText, setQueryText] = useState(activeQuery.text);
12
+ const updateQueryText = (newText) => setQueryText(newText);
13
+ const onClickSearch = () => updateActiveQuery(Object.assign(Object.assign({}, activeQuery), { text: queryText }));
14
+ const onClickReset = () => {
15
+ updateQueryText("");
16
+ resetActiveQuery();
15
17
  };
16
- 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, {}))] }));
18
+ return (_jsxs(BaseGrantMatch, { children: [_jsx(GrantMatchActions, { queryText: queryText, updateQueryText: updateQueryText, onClickSearch: onClickSearch, onClickFileDrop: () => openModal(), onClickReset: onClickReset, isActive: activeQuery.text !== "" }), activeQuery.files.length > 0 ? (_jsxs(ActiveQueryRow, { children: [_jsx(ActiveQueryFiles, { activeQuery: activeQuery, removeQueryFile: removeActiveQueryFile, removeQueryText: removeActiveQueryText }), _jsx(SmallScreenResetButton, { onClick: onClickReset })] })) : (_jsx(_Fragment, {})), showModal ? (_jsx(GrantMatchModal, { activeQuery: activeQuery, updateActiveQuery: updateActiveQuery, queryText: queryText, updateQueryText: updateQueryText, closeModal: closeModal })) : (_jsx(_Fragment, {}))] }));
17
19
  };
18
20
  export default GrantMatch;
19
- export const useGrantMatchQueryItems = (performGrantMatch, resetGrantMatch) => {
20
- const [query, setQuery] = useState(() => (Object.assign({}, BLANK_GRANT_MATCH_QUERY)));
21
- const updateQuery = (newQuery) => {
22
- setQuery(Object.assign({}, newQuery));
23
- if (isGrantMatchActive(newQuery)) {
24
- performGrantMatch(newQuery);
21
+ // TODO: refactor
22
+ export const useGrantMatchActiveQuery = (filters, performGrantMatch, resetGrantMatch) => {
23
+ const [activeQuery, setActiveQuery] = useState(() => (Object.assign({}, BLANK_GRANT_MATCH_QUERY)));
24
+ const updateActiveQuery = (query) => {
25
+ setActiveQuery(Object.assign({}, query));
26
+ if (isGrantMatchActive(query)) {
27
+ performGrantMatch(query, filters);
25
28
  }
26
29
  else {
27
30
  resetGrantMatch();
28
31
  }
29
32
  };
30
- const removeQueryFile = (fileName) => {
33
+ const removeActiveQueryFile = (fileName) => {
31
34
  const newQuery = {
32
- files: query.files.filter((file) => file.name !== fileName),
33
- text: query.text,
35
+ files: activeQuery.files.filter((file) => file.name !== fileName),
36
+ text: activeQuery.text,
34
37
  };
35
- updateQuery(newQuery);
36
- if (isGrantMatchActive(newQuery)) {
37
- performGrantMatch(newQuery);
38
- }
39
- else {
40
- resetGrantMatch();
41
- }
42
- };
43
- const removeQueryText = () => {
44
- const newQuery = { files: query.files, text: "" };
45
- updateQuery(newQuery);
46
- if (isGrantMatchActive(newQuery)) {
47
- performGrantMatch(newQuery);
48
- }
49
- else {
50
- resetGrantMatch();
51
- }
38
+ updateActiveQuery(newQuery);
52
39
  };
53
- const resetQuery = () => {
54
- setQuery(Object.assign({}, BLANK_GRANT_MATCH_QUERY));
55
- resetGrantMatch();
40
+ const removeActiveQueryText = () => {
41
+ const newQuery = { files: activeQuery.files, text: "" };
42
+ updateActiveQuery(newQuery);
56
43
  };
44
+ const resetActiveQuery = () => updateActiveQuery(Object.assign({}, BLANK_GRANT_MATCH_QUERY));
57
45
  return {
58
- query,
59
- updateQuery,
60
- removeQueryFile,
61
- removeQueryText,
62
- resetQuery,
46
+ activeQuery,
47
+ updateActiveQuery,
48
+ removeActiveQueryFile,
49
+ removeActiveQueryText,
50
+ resetActiveQuery,
63
51
  };
64
52
  };
65
53
  const BLANK_GRANT_MATCH_QUERY = { files: [], text: "" };
@@ -71,50 +59,120 @@ const BaseGrantMatch = styled.div `
71
59
  width: 100%;
72
60
  max-width: 100vw;
73
61
  `;
74
- 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, {}))] }));
75
- const Buttons = styled.div `
62
+ const GrantMatchActions = ({ queryText, updateQueryText, onClickSearch, onClickFileDrop, onClickReset, isActive, }) => (_jsxs(Actions, { children: [_jsxs(SearchBar, { "$isActive": isActive, children: [_jsx(Input, { value: queryText, onChange: (event) => updateQueryText(event.target.value), placeholder: "Find grants that match your needs" }), _jsx(SearchButton, { onClick: onClickSearch }), _jsx(FileDropButton, { onClick: onClickFileDrop })] }), isActive ? _jsx(BigScreenResetButton, { onClick: onClickReset }) : _jsx(_Fragment, {})] }));
63
+ const Actions = styled.div `
76
64
  display: flex;
77
65
  align-items: center;
78
66
  gap: 8px;
79
67
  `;
80
- 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 })] }));
81
- const BaseGrantMatchButton = styled.button `
68
+ const SearchBar = styled.div `
82
69
  display: flex;
83
70
  align-items: center;
84
- justify-content: space-between;
85
- gap: 16px;
86
71
 
87
- padding: 10px 16px;
88
-
89
- height: 20px;
90
- width: ${({ $isSmallerThanLaptop = false }) => $isSmallerThanLaptop ? "100%" : "auto"};
91
-
92
- font-size: 14px;
93
- font-weight: 500;
72
+ padding: 6px 16px;
94
73
 
95
74
  background-color: ${Colors.base.white};
96
- color: ${Colors.typography.blackMedium};
75
+ color: ${Colors.typography.blackHigh};
97
76
 
98
77
  border: 1px solid
99
78
  ${({ $isActive }) => $isActive ? Colors.accent.yellow1 : Colors.neutral.grey3};
100
- border-radius: 200px;
79
+ border-radius: 12px;
80
+
81
+ @media (width < ${Responsive.WIDTH_BREAKPOINTS.laptop}) {
82
+ gap: 8px;
83
+ width: 100%;
84
+ }
85
+
86
+ @media (width >= ${Responsive.WIDTH_BREAKPOINTS.laptop}) {
87
+ gap: 16px;
88
+ width: auto;
89
+ }
90
+ `;
91
+ const Input = styled.input `
92
+ width: 300px;
93
+ border: none;
94
+ outline: none;
101
95
  `;
102
- const GrantMatchButtonContent = styled.div `
96
+ const SearchButton = ({ onClick }) => (_jsx(BaseSearchButton, { type: "button", onClick: onClick, children: _jsx(Icons.MagnifyingGlassIcon, { size: 16, color: Colors.neutral.grey1 }) }));
97
+ const BaseSearchButton = styled.button `
103
98
  display: flex;
104
99
  align-items: center;
105
- gap: 8px;
100
+ justify-content: center;
101
+
102
+ height: 32px;
103
+ width: 32px;
104
+ min-width: 32px;
105
+
106
+ background-color: ${Colors.neutral.grey3};
107
+
108
+ border-radius: 8px;
109
+ `;
110
+ const FileDropButton = ({ onClick }) => (_jsxs(BaseFileDropButton, { onClick: onClick, children: [_jsx(Icons.FileArrowUpIcon, { size: 16 }), _jsx(FileDropButtonText, { children: "File Drop" })] }));
111
+ const BaseFileDropButton = styled.button `
112
+ display: flex;
113
+ align-items: center;
114
+ justify-content: center;
115
+ gap: 4px;
116
+
117
+ height: 31px;
118
+ min-width: 31px;
119
+
120
+ background-color: ${Colors.base.white};
121
+ color: ${Colors.accent.blue1};
122
+
123
+ border: 1px solid ${Colors.accent.blue1};
124
+ border-radius: 8px;
125
+
126
+ @media (width < ${Responsive.WIDTH_BREAKPOINTS.laptop}) {
127
+ padding: 0px;
128
+ font-size: ${Typography.HELPER_FONT_SIZES.small};
129
+ }
130
+
131
+ @media (width >= ${Responsive.WIDTH_BREAKPOINTS.laptop}) {
132
+ padding: 0px 8px;
133
+ font-size: ${Typography.HELPER_FONT_SIZES.big};
134
+ }
135
+ `;
136
+ const FileDropButtonText = styled.p `
137
+ @media (width < ${Responsive.WIDTH_BREAKPOINTS.laptop}) {
138
+ display: none;
139
+ }
140
+
141
+ @media (width >= ${Responsive.WIDTH_BREAKPOINTS.laptop}) {
142
+ display: inline;
143
+ }
144
+ `;
145
+ const SmallScreenResetButton = ({ onClick }) => (_jsx(SmallScreenReset, { children: _jsx(ResetButton, { onClick: onClick }) }));
146
+ const SmallScreenReset = styled.div `
147
+ @media (width < ${Responsive.WIDTH_BREAKPOINTS.laptop}) {
148
+ display: inline;
149
+ }
150
+
151
+ @media (width >= ${Responsive.WIDTH_BREAKPOINTS.laptop}) {
152
+ display: none;
153
+ }
154
+ `;
155
+ const BigScreenResetButton = ({ onClick }) => (_jsx(BigScreenReset, { children: _jsx(ResetButton, { onClick: onClick }) }));
156
+ const BigScreenReset = styled.div `
157
+ @media (width < ${Responsive.WIDTH_BREAKPOINTS.laptop}) {
158
+ display: none;
159
+ }
160
+
161
+ @media (width >= ${Responsive.WIDTH_BREAKPOINTS.laptop}) {
162
+ display: inline;
163
+ }
106
164
  `;
107
165
  const ResetButton = ({ onClick }) => (_jsx(Button, { text: "Reset", onClick: onClick, color: Colors.typography.blackMedium, underline: true }));
108
- const QueryItemsRow = styled.div `
166
+ const ActiveQueryRow = styled.div `
109
167
  display: flex;
110
168
  align-items: center;
111
169
  justify-content: space-between;
112
170
  `;
113
- const QueryItems = ({ activeQuery, removeQueryFile, removeQueryText, }) => (_jsxs(BaseQueryItems, { children: [activeQuery.files.map((file) => {
114
- var _a;
115
- 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));
116
- }), activeQuery.text === "" ? (_jsx(_Fragment, {})) : (_jsx(Badge, { text: "Additional Information", Icon: Icons.TextAaIcon, onClickClose: () => removeQueryText(), textWidthPixels: 180 }, "additional-information-query-item"))] }));
117
- const BaseQueryItems = styled.div `
171
+ const ActiveQueryFiles = ({ activeQuery, removeQueryFile, }) => (_jsx(BaseActiveQueryFiles, { children: activeQuery.files.map((file) => {
172
+ var _a;
173
+ 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));
174
+ }) }));
175
+ const BaseActiveQueryFiles = styled.div `
118
176
  display: flex;
119
177
  align-items: center;
120
178
  gap: 8px;
@@ -135,19 +193,16 @@ const BaseQueryItems = styled.div `
135
193
  const FILE_TYPE_ICON_MAP = {
136
194
  "application/pdf": Icons.FilePdfIcon,
137
195
  };
138
- const GrantMatchModal = ({ activeQuery, updateActiveQuery, onClickCancel, isFullScreen, }) => {
196
+ const GrantMatchModal = ({ activeQuery, updateActiveQuery, queryText, updateQueryText, closeModal, }) => {
139
197
  const { files, uploadFiles, removeFile } = useFileDrop(activeQuery.files);
140
- const [text, setText] = useState(activeQuery.text);
141
- 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", height: "600px" }));
198
+ const onClickFind = () => {
199
+ updateActiveQuery({ files, text: queryText });
200
+ closeModal();
201
+ };
202
+ return (_jsx(Modal, { header: _jsx("div", { children: "Grant Match" }), content: _jsx(Content, { files: files, uploadFiles: uploadFiles, removeFile: removeFile, queryText: queryText, updateQueryText: updateQueryText }), footer: _jsx(Button, { text: "Find My Grants", onClick: onClickFind, backgroundColor: Colors.accent.yellow1 }), onClickCancel: () => closeModal(), width: "480px", height: "600px" }));
142
203
  };
143
- const Header = () => (_jsxs(BaseHeader, { children: [_jsx(Icons.GrantMatchIcon, { size: 24 }), _jsx("div", { children: "Grant Match" })] }));
144
- const BaseHeader = styled.div `
145
- display: flex;
146
- align-items: center;
147
- gap: 12px;
148
- `;
149
- const Content = ({ files, uploadFiles, removeFile, queryText, updateQueryText, }) => (_jsxs(BaseContent, { children: [_jsx(FileDrop, { uploadedFiles: files, uploadFiles: uploadFiles, removeFile: removeFile }), _jsxs(QueryText, { children: [_jsx("label", { htmlFor: ADDITIONAL_INFORMATION_ID, children: "Additional Information" }), _jsx(Textarea, { id: ADDITIONAL_INFORMATION_ID, value: queryText, onChange: (event) => updateQueryText(event.target.value) })] })] }));
150
- const ADDITIONAL_INFORMATION_ID = "grant-match-additional-information";
204
+ const Content = ({ files, uploadFiles, removeFile, queryText, updateQueryText, }) => (_jsxs(BaseContent, { children: [_jsx(FileDrop, { uploadedFiles: files, uploadFiles: uploadFiles, removeFile: removeFile }), _jsxs(QueryText, { children: [_jsx("label", { htmlFor: QUERY_TEXTAREA_ID, children: "Search Grants Opportunities" }), _jsx(Textarea, { id: QUERY_TEXTAREA_ID, value: queryText, onChange: (event) => updateQueryText(event.target.value), placeholder: "Explore by grant name or share what your project is about..." })] })] }));
205
+ const QUERY_TEXTAREA_ID = "query-textarea";
151
206
  const BaseContent = styled.div `
152
207
  display: flex;
153
208
  flex-direction: column;
@@ -3,7 +3,6 @@ type TallyModalProps = {
3
3
  header?: ReactNode;
4
4
  tallyId: string;
5
5
  prefilledFieldsQueryParams?: string;
6
- isFullScreen?: boolean;
7
6
  onClickCancel: MouseEventHandler<HTMLButtonElement>;
8
7
  };
9
8
  declare const TallyModal: ({ tallyId, prefilledFieldsQueryParams, ...modalProps }: TallyModalProps) => import("react/jsx-runtime").JSX.Element;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@grantbii/design-system",
3
- "version": "1.0.66",
3
+ "version": "1.0.68",
4
4
  "description": "Grantbii's Design System",
5
5
  "homepage": "https://design.grantbii.com",
6
6
  "repository": {
@@ -18,7 +18,7 @@
18
18
  "build-storybook": "storybook build"
19
19
  },
20
20
  "dependencies": {
21
- "@grantbii/ui-base": "1.0.17",
21
+ "@grantbii/ui-base": "1.0.18",
22
22
  "@phosphor-icons/react": "^2.1.10",
23
23
  "country-flag-icons": "^1.5.19",
24
24
  "next": "^15.5.0",
@@ -6,13 +6,10 @@ type ModalExampleProps = {
6
6
  footer?: ReactNode;
7
7
  width?: string;
8
8
  height?: string;
9
- isFullScreen?: boolean;
10
9
  };
11
10
  declare const ModalExample: (props: ModalExampleProps) => import("react/jsx-runtime").JSX.Element;
12
11
  declare const meta: Meta<typeof ModalExample>;
13
12
  export default meta;
14
13
  type Story = StoryObj<typeof meta>;
15
- export declare const PopUpWithShortContent: Story;
16
- export declare const FullScreenWithShortContent: Story;
17
- export declare const PopUpWithLongContent: Story;
18
- export declare const FullScreenWithLongContent: Story;
14
+ export declare const ShortContent: Story;
15
+ export declare const LongContent: Story;