nitro-web 0.0.66 → 0.0.67

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.
@@ -1,9 +1,10 @@
1
1
  import { css } from 'twin.macro'
2
2
  import { forwardRef, cloneElement } from 'react'
3
- import { getSelectStyle } from 'nitro-web'
3
+ import { getSelectStyle, twMerge } from 'nitro-web'
4
4
  import { CheckCircleIcon } from '@heroicons/react/24/solid'
5
5
 
6
6
  type DropdownProps = {
7
+ allowOverflow?: boolean
7
8
  animate?: boolean
8
9
  children?: React.ReactNode
9
10
  className?: string
@@ -18,20 +19,23 @@ type DropdownProps = {
18
19
  /** The content to render inside the top of the dropdown **/
19
20
  menuContent?: React.ReactNode
20
21
  menuClassName?: string
22
+ menuOptionClassName?: string
21
23
  menuIsOpen?: boolean
22
24
  menuToggles?: boolean
23
25
  toggleCallback?: (isActive: boolean) => void
24
26
  }
25
27
 
26
28
  export const Dropdown = forwardRef(function Dropdown({
29
+ allowOverflow=false,
27
30
  animate=true,
28
31
  children,
29
32
  className,
30
33
  dir,
31
34
  options,
32
35
  isHoverable,
33
- minWidth,
36
+ minWidth, // remove in favour of menuClassName
34
37
  menuClassName,
38
+ menuOptionClassName,
35
39
  menuContent,
36
40
  menuIsOpen,
37
41
  menuToggles=true,
@@ -92,6 +96,7 @@ export const Dropdown = forwardRef(function Dropdown({
92
96
  (isHoverable ? ' is-hoverable' : '') +
93
97
  (isActive ? ' is-active' : '') +
94
98
  (!animate ? ' no-animation' : '') +
99
+ (allowOverflow ? ' is-allowOverflow' : '') +
95
100
  ' nitro-dropdown' +
96
101
  (className ? ` ${className}` : '')
97
102
  }
@@ -108,7 +113,7 @@ export const Dropdown = forwardRef(function Dropdown({
108
113
  }
109
114
  <ul
110
115
  style={{ minWidth }}
111
- class={`${menuStyle} absolute invisible opacity-0 select-none min-w-full z-[1] ${menuClassName}`}
116
+ class={twMerge(`${menuStyle} absolute invisible opacity-0 select-none min-w-full z-[1] ${menuClassName}`)}
112
117
  >
113
118
  {menuContent}
114
119
  {
@@ -117,7 +122,7 @@ export const Dropdown = forwardRef(function Dropdown({
117
122
  return (
118
123
  <li
119
124
  key={i}
120
- className={`${optionStyle} ${option.className}`}
125
+ className={twMerge(`${optionStyle} ${option.className} ${menuOptionClassName}`)}
121
126
  onClick={(e: React.MouseEvent) => onClick(option, e)}
122
127
  >
123
128
  <span class="flex-auto">{option.label}</span>
@@ -137,8 +142,7 @@ const style = css`
137
142
  transition: transform 0.15s ease, opacity 0.15s ease, visibility 0s 0.15s ease, max-width 0s 0.15s ease, max-height 0s 0.15s ease;
138
143
  max-width: 0; // handy if the dropdown ul exceeds the viewport width
139
144
  max-height: 0; // handy if the dropdown ul exceeds the viewport height
140
- /* overflow: visible !important; // override menustyle */
141
- pointer-events: none;
145
+ pointer-events: none;
142
146
  }
143
147
  &.is-bottom-right,
144
148
  &.is-top-right {
@@ -175,6 +179,8 @@ const style = css`
175
179
  max-width: 1000px;
176
180
  max-height: 1000px;
177
181
  pointer-events: auto;
182
+ }
183
+ &.is-allowOverflow > ul {
178
184
  overflow: visible;
179
185
  }
180
186
  &.is-bottom-left > ul,
@@ -33,6 +33,7 @@ type FiltersProps = {
33
33
  buttonText?: string
34
34
  buttonCounterClassName?: string
35
35
  filtersContainerClassName?: string
36
+ menuClassName?: string
36
37
  }
37
38
 
38
39
  export type FiltersHandleType = {
@@ -52,6 +53,7 @@ export const Filters = forwardRef<FiltersHandleType, FiltersProps>(({
52
53
  dropdownProps,
53
54
  elements,
54
55
  filtersContainerClassName,
56
+ menuClassName,
55
57
  }, ref) => {
56
58
  const location = useLocation()
57
59
  const navigate = useNavigate()
@@ -119,18 +121,22 @@ export const Filters = forwardRef<FiltersHandleType, FiltersProps>(({
119
121
  navigate(location.pathname + queryStr, { replace: true })
120
122
  }
121
123
 
122
- // if (!filters) return null
123
124
  return (
124
125
  <Elements.Dropdown
125
126
  dir="bottom-right"
127
+ allowOverflow={true}
126
128
  // menuIsOpen={true}
127
- menuClassName="!rounded-lg"
129
+ menuClassName={twMerge(`!rounded-lg min-w-[330px] ${menuClassName || ''}`)}
128
130
  menuContent={
129
- <div class="w-[330px]">
131
+ <div>
130
132
  <div class="flex justify-between items-center border-b p-4 py-3.5">
131
133
  <div class="text-lg font-semibold">Filters</div>
132
134
  <Button color="clear" size="sm" onClick={resetAll}>Reset All</Button>
133
135
  </div>
136
+ {/* <div class="w-[1330px] bg-red-500 absolute">
137
+ This div shouldnt produce a page scrollbar when the dropdown is closed.
138
+ But should be visibile if allowedOverflow is true.
139
+ </div> */}
134
140
  <div class={twMerge(`flex flex-wrap gap-4 px-4 py-4 pb-6 ${filtersContainerClassName || ''}`)}>
135
141
  {
136
142
  filters?.map(({label, rowClassName, ...filter}, i) => (
@@ -69,8 +69,11 @@ export function FieldDate({
69
69
 
70
70
  // Convert the value to an array of valid* dates
71
71
  const dates = useMemo(() => {
72
- const _dates = Array.isArray(value) ? value : [value]
73
- return _dates.map(date => isValid(date) ? new Date(date as number) : null) /// change to null
72
+ const arrOfNumbers = typeof value === 'string'
73
+ ? value.split(/\s*,\s*/g).map(o => parseFloat(o))
74
+ : Array.isArray(value) ? value : [value]
75
+ const out = arrOfNumbers.map(date => isValid(date) ? new Date(date as number) : null) /// changed to null
76
+ return out
74
77
  }, [value])
75
78
 
76
79
  // Hold the input value in state
@@ -79,7 +82,7 @@ export function FieldDate({
79
82
  // Update the date's inputValue (text) when the value changes outside of the component
80
83
  useEffect(() => {
81
84
  if (new Date().getTime() > lastUpdated + 100) setInputValue(getInputValue(dates))
82
- }, [value])
85
+ }, [dates])
83
86
 
84
87
  // Get the prefix content width
85
88
  useEffect(() => {
@@ -90,15 +93,10 @@ export function FieldDate({
90
93
  if (mode == 'single' && !showTime) dropdownRef.current?.setIsActive(false) // Close the dropdown
91
94
  setInputValue(getInputValue(value))
92
95
  // Update the value
93
- onChange({ target: { name: props.name, value: value as any } })
96
+ onChange({ target: { name: props.name, value: getOutputValue(value) } })
94
97
  setLastUpdated(new Date().getTime())
95
98
  }
96
99
 
97
- function getInputValue(dates: Date|number|null|(Date|number|null)[]) {
98
- const _dates = Array.isArray(dates) ? dates : [dates]
99
- return _dates.map(o => o ? format(o, localePattern) : '').join(mode == 'range' ? ' - ' : ', ')
100
- }
101
-
102
100
  function onInputChange(e: React.ChangeEvent<HTMLInputElement>) {
103
101
  setInputValue(e.target.value) // keep the input value in sync
104
102
 
@@ -122,10 +120,20 @@ export function FieldDate({
122
120
 
123
121
  // Update the value
124
122
  const value = mode == 'single' ? split[0]?.getTime() ?? null : split.map(d => d?.getTime() ?? null)
125
- onChange({ target: { name: props.name, value: value as any }})
123
+ onChange({ target: { name: props.name, value: getOutputValue(value) }})
126
124
  setLastUpdated(new Date().getTime())
127
125
  }
128
126
 
127
+ function getInputValue(value: Date|number|null|(Date|number|null)[]) {
128
+ const _dates = Array.isArray(value) ? value : [value]
129
+ return _dates.map(o => o ? format(o, localePattern) : '').join(mode == 'range' ? ' - ' : ', ')
130
+ }
131
+
132
+ function getOutputValue(value: Date|number|null|(Date|number|null)[]): any {
133
+ // console.log(value)
134
+ return value
135
+ }
136
+
129
137
  return (
130
138
  <Dropdown
131
139
  ref={dropdownRef}
@@ -136,7 +144,8 @@ export function FieldDate({
136
144
  menuContent={
137
145
  <div className="flex">
138
146
  <Calendar
139
- {...{ mode, value, numberOfMonths, month }}
147
+ // Calendar actually accepts an array of dates, but the type is not typed correctly
148
+ {...{ mode: mode, value: dates as any, numberOfMonths: numberOfMonths, month: month }}
140
149
  preserveTime={!!showTime}
141
150
  onChange={onCalendarChange}
142
151
  className="pt-1 pb-2 px-3"
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "nitro-web",
3
- "version": "0.0.66",
3
+ "version": "0.0.67",
4
4
  "repository": "github:boycce/nitro-web",
5
5
  "homepage": "https://boycce.github.io/nitro-web/",
6
6
  "description": "Nitro is a battle-tested, modular base project to turbocharge your projects, styled using Tailwind 🚀",
package/util.js CHANGED
@@ -1255,9 +1255,9 @@ export function parseFilters(query, config) {
1255
1255
  } else if (rule === 'dateRange') {
1256
1256
  const [start, end] = val.split(',').map(Number)
1257
1257
  if (isNaN(start) && isNaN(end)) throw new Error(`The "${key}" filter has an invalid value "${val}". Expected a date range.`)
1258
- else if (isNaN(start)) mongoQuery.date = { $gte: 0, $lte: end }
1259
- else if (isNaN(end)) mongoQuery.date = { $gte: start }
1260
- else mongoQuery.date = { $gte: start, $lte: end }
1258
+ else if (isNaN(start)) mongoQuery[key] = { $gte: 0, $lte: end }
1259
+ else if (isNaN(end)) mongoQuery[key] = { $gte: start }
1260
+ else mongoQuery[key] = { $gte: start, $lte: end }
1261
1261
 
1262
1262
  } else {
1263
1263
  throw new Error(`Unknown filter type "${rule}" in the config.`)