@npm_leadtech/legal-lib-components 7.22.0 → 7.22.3

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.
@@ -6,58 +6,56 @@ export const SearchBarStyled = styled.div`
6
6
  .search {
7
7
  width: calc(100% - 3rem);
8
8
  margin: 0 1.5rem;
9
+ }
10
+ }
9
11
 
10
- @media ${device['landscape-tablets']} {
11
- display: none;
12
- }
13
-
14
- @media ${device['landscape-tablets']} {
15
- display: block;
16
- width: 10rem;
17
- margin: 0 1.5rem 0 0;
12
+ @media ${device['landscape-tablets']} {
13
+ &.modal_searchbar {
14
+ position: fixed;
15
+ top: 0;
16
+ left: 0;
17
+ width: 100vw;
18
+ height: 100vh;
19
+ background: rgba(255, 255, 255, 0.95);
20
+ z-index: 9999;
21
+ display: flex;
22
+ justify-content: center;
23
+ align-items: flex-start;
24
+ padding-top: 100px;
25
+
26
+ .modal_searchbar__content {
27
+ background-color: var(--neutral-white);
28
+ padding: 1.5rem;
29
+ border-radius: 8px;
30
+ width: 90%;
31
+ max-width: 768px;
32
+ box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
33
+
34
+ @media ${device['landscape-tablets']} {
35
+ padding: 0;
36
+ border-radius: 8px 8px 0 0;
37
+ }
18
38
  }
19
39
 
20
- @media ${device['desktop']} {
21
- width: 14rem;
40
+ .modal_searchbar__header {
41
+ display: flex;
42
+ justify-content: space-between;
43
+ align-items: center;
44
+ margin-bottom: 1rem;
22
45
  }
23
46
 
24
- .dropdown_input__results {
25
- transition: all 0.25s;
26
- min-width: 100%;
27
- width: max-content;
47
+ .modal_searchbar__title {
48
+ font-size: 1.5rem;
49
+ font-weight: bold;
50
+ color: var(--others-black);
28
51
  }
29
52
 
30
- .dropdown_input__link {
31
- color: var(--neutral-neutral-3);
32
- animation: newLine 0.5s;
33
-
34
- &:hover {
35
- color: var(--others-black);
36
- }
37
-
38
- &__emphasis {
39
- font-style: normal;
40
- font-weight: normal;
41
- color: var(--others-black);
42
- }
43
-
44
- &--all {
45
- font-weight: bold;
46
- animation: none;
53
+ .dropdown_input {
54
+ .search {
55
+ width: 100%;
56
+ margin: 0;
47
57
  }
48
58
  }
49
59
  }
50
60
  }
51
-
52
- @keyframes newLine {
53
- 0% {
54
- opacity: 0;
55
- line-height: 0rem;
56
- }
57
-
58
- 100% {
59
- opacity: 1;
60
- line-height: 1.5rem;
61
- }
62
- }
63
61
  `
@@ -1,66 +1,106 @@
1
- import React, { useState } from 'react'
2
-
1
+ import React, { useEffect, useRef } from 'react'
3
2
  import { DropdownInput } from '../../atoms/DropdownInput/DropdownInput'
4
3
  import { SearchIcon } from '../../../../images/componentsSvg/SearchIcon'
5
4
  import { useWindowSize } from '../../../hooks/useWindowSize'
6
5
 
7
6
  import { type SearchBarProps } from './SearchBarProps.types'
8
7
  import { SearchBarStyled } from './SearchBar.styled'
8
+ import { useSearchFunction } from '../../../hooks/useSearchFunction'
9
9
 
10
- export const SearchBar: React.FC<SearchBarProps> = ({ products, searchBarTexts, routes, handleResultClick }) => {
11
- const [results, setResults] = useState<React.JSX.Element[]>([])
10
+ const DesktopSearchBar: React.FC<SearchBarProps> = ({ products, searchBarTexts, routes, handleResultClick }) => {
11
+ const { results, searchFunction } = useSearchFunction({
12
+ products,
13
+ searchBarTexts,
14
+ routes,
15
+ handleResultClick
16
+ })
17
+ const searchInputRef = useRef<HTMLInputElement>(null)
18
+ const searchBarContainerRef = useRef<HTMLDivElement>(null)
19
+ const isResultsVisible = Array.isArray(results) && results.length > 0
12
20
 
13
- const windowSize = useWindowSize()
14
- const _placeholder = windowSize.width === null || windowSize.width >= 720 ? '' : searchBarTexts.placeholder
15
- const searchFunction = (text: string): void => {
16
- const searchTerm = text.toLowerCase()
21
+ useEffect(() => {
22
+ const handleKeyDown = (event: KeyboardEvent) => {
23
+ if (event.key === 'Escape') {
24
+ searchFunction('')
25
+ }
26
+ }
27
+ const handleClickOutside = (event: MouseEvent) => {
28
+ if (searchBarContainerRef.current && !searchBarContainerRef.current.contains(event.target as Node)) {
29
+ searchFunction('')
30
+ }
31
+ }
17
32
 
18
- const productsFiltered = products.filter((item) => item.linkText.toLowerCase().includes(searchTerm))
19
- const results = productsFiltered
20
- .map((item) => {
21
- const product = item.linkText
22
- const preMatch = product.slice(0, product.toLowerCase().indexOf(searchTerm))
23
- const match = product.slice(product.toLowerCase().indexOf(searchTerm), preMatch.length + searchTerm.length)
24
- const postMatch = product.slice(product.toLowerCase().indexOf(searchTerm) + searchTerm.length, product.length)
25
- const link = item.categoryUrl ? `${item.categoryUrl}/${item.slug}` : item.slug
26
- return (
27
- <li key={searchBarTexts.title} className='dropdown_input__item'>
28
- <a
29
- href={routes.CUSTOM_URL_FROM_TARGET_ADDRESS(link)}
30
- className='dropdown_input__link'
31
- key={item.linkText}
32
- onClick={(e) => {
33
- e.preventDefault()
34
- handleResultClick(product, routes.CUSTOM_URL_FROM_TARGET_ADDRESS(link))
35
- }}
36
- title={product}
37
- >
38
- {preMatch}
39
- <strong className='dropdown_input__link__emphasis'>{match}</strong>
40
- {postMatch}
41
- </a>
42
- </li>
43
- )
44
- })
45
- .slice(0, 9)
33
+ if (isResultsVisible) {
34
+ document.addEventListener('keydown', handleKeyDown)
35
+ document.addEventListener('mousedown', handleClickOutside)
36
+ }
46
37
 
47
- results.push(
48
- <li key={searchBarTexts.title} className='dropdown_input__item'>
49
- <a className='dropdown_input__link--all' title={searchBarTexts.title} href={routes.LEGAL_DOCUMENTS}>
50
- {searchBarTexts.title}
51
- </a>
52
- </li>
53
- )
38
+ return () => {
39
+ document.removeEventListener('keydown', handleKeyDown)
40
+ document.removeEventListener('mousedown', handleClickOutside)
41
+ }
42
+ }, [isResultsVisible, searchFunction])
54
43
 
55
- setResults(results)
56
- }
44
+ return (
45
+ <SearchBarStyled ref={searchBarContainerRef} className='modal_searchbar'>
46
+ <div className='modal_searchbar__content'>
47
+ <DropdownInput
48
+ ref={searchInputRef}
49
+ name='search'
50
+ className='search'
51
+ placeholder={searchBarTexts.placeholder}
52
+ icon={<SearchIcon />}
53
+ onChange={(text: string) => {
54
+ searchFunction(text)
55
+ }}
56
+ results={results}
57
+ />
58
+ </div>
59
+ </SearchBarStyled>
60
+ )
61
+ }
62
+
63
+ const MobileSearchBar: React.FC<SearchBarProps> = ({ products, searchBarTexts, routes, handleResultClick }) => {
64
+ const { results, searchFunction } = useSearchFunction({
65
+ products,
66
+ searchBarTexts,
67
+ routes,
68
+ handleResultClick
69
+ })
70
+ const searchInputRef = useRef<HTMLInputElement>(null)
71
+ const searchBarContainerRef = useRef<HTMLDivElement>(null)
72
+ const isResultsVisible = Array.isArray(results) && results.length > 0
73
+
74
+ useEffect(() => {
75
+ const handleKeyDown = (event: KeyboardEvent) => {
76
+ if (event.key === 'Escape') {
77
+ searchFunction('')
78
+ }
79
+ }
80
+ const handleClickOutside = (event: MouseEvent) => {
81
+ if (searchBarContainerRef.current && !searchBarContainerRef.current.contains(event.target as Node)) {
82
+ searchFunction('')
83
+ }
84
+ }
85
+
86
+ if (isResultsVisible) {
87
+ document.addEventListener('keydown', handleKeyDown)
88
+ document.addEventListener('mousedown', handleClickOutside)
89
+ }
90
+
91
+ return () => {
92
+ document.removeEventListener('keydown', handleKeyDown)
93
+ document.removeEventListener('mousedown', handleClickOutside)
94
+ }
95
+ }, [isResultsVisible, searchFunction])
57
96
 
58
97
  return (
59
- <SearchBarStyled>
98
+ <SearchBarStyled ref={searchBarContainerRef}>
60
99
  <DropdownInput
100
+ ref={searchInputRef}
61
101
  name='search'
62
102
  className='search'
63
- placeholder={_placeholder}
103
+ placeholder={searchBarTexts.placeholder}
64
104
  icon={<SearchIcon />}
65
105
  onChange={(text: string) => {
66
106
  searchFunction(text)
@@ -70,3 +110,14 @@ export const SearchBar: React.FC<SearchBarProps> = ({ products, searchBarTexts,
70
110
  </SearchBarStyled>
71
111
  )
72
112
  }
113
+
114
+ export const SearchBar: React.FC<SearchBarProps> = (props) => {
115
+ const windowSize = useWindowSize()
116
+ const isDesktop = !!windowSize.width && windowSize.width >= 960
117
+
118
+ if (isDesktop) {
119
+ return <DesktopSearchBar {...props} />
120
+ }
121
+
122
+ return <MobileSearchBar {...props} />
123
+ }
@@ -0,0 +1,10 @@
1
+ import React from 'react';
2
+ import { type SearchBarProps } from '../components/molecules/SearchBar/SearchBarProps.types';
3
+ interface SearchFunctionProps extends SearchBarProps {
4
+ onClose?: () => void;
5
+ }
6
+ export declare const useSearchFunction: (props: SearchFunctionProps) => {
7
+ results: React.JSX.Element[];
8
+ searchFunction: (text: string) => void;
9
+ };
10
+ export {};
@@ -0,0 +1,28 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { useState } from 'react';
3
+ export const useSearchFunction = (props) => {
4
+ const [results, setResults] = useState([]);
5
+ const searchFunction = (text) => {
6
+ const { products, searchBarTexts, routes, handleResultClick, onClose } = props;
7
+ const searchTerm = text.toLowerCase();
8
+ const productsFiltered = products.filter((item) => item.linkText.toLowerCase().includes(searchTerm));
9
+ const newResults = productsFiltered
10
+ .map((item) => {
11
+ const product = item.linkText;
12
+ const preMatch = product.slice(0, product.toLowerCase().indexOf(searchTerm));
13
+ const match = product.slice(product.toLowerCase().indexOf(searchTerm), preMatch.length + searchTerm.length);
14
+ const postMatch = product.slice(product.toLowerCase().indexOf(searchTerm) + searchTerm.length, product.length);
15
+ const link = item.categoryUrl ? `${item.categoryUrl}/${item.slug}` : item.slug;
16
+ return (_jsx("li", { className: 'dropdown_input__item', children: _jsxs("a", { href: routes.CUSTOM_URL_FROM_TARGET_ADDRESS(link), className: 'dropdown_input__link', onClick: (e) => {
17
+ e.preventDefault();
18
+ handleResultClick(product, routes.CUSTOM_URL_FROM_TARGET_ADDRESS(link));
19
+ if (onClose)
20
+ onClose();
21
+ }, title: product, children: [preMatch, _jsx("strong", { className: 'dropdown_input__link__emphasis', children: match }), postMatch] }) }, item.linkText));
22
+ })
23
+ .slice(0, 9);
24
+ newResults.push(_jsx("li", { className: 'dropdown_input__item', children: _jsx("a", { className: 'dropdown_input__link--all', title: searchBarTexts.title, href: routes.LEGAL_DOCUMENTS, onClick: onClose, children: searchBarTexts.title }) }, searchBarTexts.title));
25
+ setResults(newResults);
26
+ };
27
+ return { results, searchFunction };
28
+ };
@@ -0,0 +1,63 @@
1
+ import React, { useState } from 'react'
2
+ import { type SearchBarProps } from '../components/molecules/SearchBar/SearchBarProps.types'
3
+
4
+ interface SearchFunctionProps extends SearchBarProps {
5
+ onClose?: () => void
6
+ }
7
+
8
+ export const useSearchFunction = (props: SearchFunctionProps) => {
9
+ const [results, setResults] = useState<React.JSX.Element[]>([])
10
+
11
+ const searchFunction = (text: string): void => {
12
+ const { products, searchBarTexts, routes, handleResultClick, onClose } = props
13
+ const searchTerm = text.toLowerCase()
14
+
15
+ const productsFiltered = products.filter((item) => item.linkText.toLowerCase().includes(searchTerm))
16
+
17
+ const newResults = productsFiltered
18
+ .map((item) => {
19
+ const product = item.linkText
20
+ const preMatch = product.slice(0, product.toLowerCase().indexOf(searchTerm))
21
+ const match = product.slice(product.toLowerCase().indexOf(searchTerm), preMatch.length + searchTerm.length)
22
+ const postMatch = product.slice(product.toLowerCase().indexOf(searchTerm) + searchTerm.length, product.length)
23
+ const link = item.categoryUrl ? `${item.categoryUrl}/${item.slug}` : item.slug
24
+
25
+ return (
26
+ <li key={item.linkText} className='dropdown_input__item'>
27
+ <a
28
+ href={routes.CUSTOM_URL_FROM_TARGET_ADDRESS(link)}
29
+ className='dropdown_input__link'
30
+ onClick={(e) => {
31
+ e.preventDefault()
32
+ handleResultClick(product, routes.CUSTOM_URL_FROM_TARGET_ADDRESS(link))
33
+ if (onClose) onClose()
34
+ }}
35
+ title={product}
36
+ >
37
+ {preMatch}
38
+ <strong className='dropdown_input__link__emphasis'>{match}</strong>
39
+ {postMatch}
40
+ </a>
41
+ </li>
42
+ )
43
+ })
44
+ .slice(0, 9)
45
+
46
+ newResults.push(
47
+ <li key={searchBarTexts.title} className='dropdown_input__item'>
48
+ <a
49
+ className='dropdown_input__link--all'
50
+ title={searchBarTexts.title}
51
+ href={routes.LEGAL_DOCUMENTS}
52
+ onClick={onClose}
53
+ >
54
+ {searchBarTexts.title}
55
+ </a>
56
+ </li>
57
+ )
58
+
59
+ setResults(newResults)
60
+ }
61
+
62
+ return { results, searchFunction }
63
+ }