nitro-web 0.0.47 → 0.0.49

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/client/index.ts CHANGED
@@ -29,6 +29,7 @@ export { Avatar } from '../components/partials/element/avatar'
29
29
  export { Button } from '../components/partials/element/button'
30
30
  export { Calendar, type CalendarProps } from '../components/partials/element/calendar'
31
31
  export { Dropdown } from '../components/partials/element/dropdown'
32
+ export { Filters, type FiltersHandleType, type FilterType } from '../components/partials/element/filters'
32
33
  export { GithubLink } from '../components/partials/element/github-link'
33
34
  export { Initials } from '../components/partials/element/initials'
34
35
  export { Message } from '../components/partials/element/message'
@@ -36,7 +37,6 @@ export { Modal } from '../components/partials/element/modal'
36
37
  export { Sidebar, type SidebarProps } from '../components/partials/element/sidebar'
37
38
  export { Tooltip } from '../components/partials/element/tooltip'
38
39
  export { Topbar } from '../components/partials/element/topbar'
39
-
40
40
  // Component Form
41
41
  export { Checkbox } from '../components/partials/form/checkbox'
42
42
  export { Drop } from '../components/partials/form/drop'
@@ -233,7 +233,7 @@ export async function signinAndGetState(user, isDesktop) {
233
233
  return { ...store, jwt }
234
234
  }
235
235
 
236
- function tokenCreate(id) {
236
+ export function tokenCreate(id) {
237
237
  return new Promise((resolve) => {
238
238
  crypto.randomBytes(16, (err, buff) => {
239
239
  let hash = buff.toString('hex') // 32 chars
@@ -242,7 +242,7 @@ function tokenCreate(id) {
242
242
  })
243
243
  }
244
244
 
245
- function tokenParse(token) {
245
+ export function tokenParse(token) {
246
246
  let split = (token || '').split(':')
247
247
  let hash = split[0].slice(0, 32)
248
248
  let userId = split[0].slice(32)
@@ -2,7 +2,7 @@ import { twMerge } from 'nitro-web'
2
2
  import { ChevronDown, ChevronUp } from 'lucide-react'
3
3
 
4
4
  type Button = React.ButtonHTMLAttributes<HTMLButtonElement> & {
5
- color?: 'primary'|'secondary'|'black'|'white'
5
+ color?: 'primary'|'secondary'|'black'|'white'|'clear'
6
6
  size?: 'xs'|'sm'|'md'|'lg'
7
7
  className?: string
8
8
  isLoading?: boolean
@@ -37,6 +37,7 @@ export function Button({
37
37
  secondary: 'bg-secondary hover:bg-secondary-hover',
38
38
  black: 'bg-black hover:bg-gray-700',
39
39
  white: 'bg-white ring-1 ring-inset ring-gray-300 hover:bg-gray-50 text-gray-900 [&>.loader]:border-black',
40
+ clear: 'ring-1 ring-inset ring-gray-300 hover:bg-gray-50 text-foreground [&>.loader]:border-foreground !shadow-none',
40
41
  }
41
42
 
42
43
  // Button sizes
@@ -16,7 +16,8 @@ type DropdownProps = {
16
16
  /** The minimum width of the menu **/
17
17
  minWidth?: number | string
18
18
  /** The content to render inside the top of the dropdown **/
19
- menuChildren?: React.ReactNode
19
+ menuContent?: React.ReactNode
20
+ menuClassName?: string
20
21
  menuIsOpen?: boolean
21
22
  menuToggles?: boolean
22
23
  toggleCallback?: (isActive: boolean) => void
@@ -30,7 +31,8 @@ export const Dropdown = forwardRef(function Dropdown({
30
31
  options,
31
32
  isHoverable,
32
33
  minWidth,
33
- menuChildren,
34
+ menuClassName,
35
+ menuContent,
34
36
  menuIsOpen,
35
37
  menuToggles=true,
36
38
  toggleCallback,
@@ -39,7 +41,7 @@ export const Dropdown = forwardRef(function Dropdown({
39
41
  isHoverable = isHoverable && !menuIsOpen
40
42
  const dropdownRef = useRef<HTMLDivElement|null>(null)
41
43
  const [isActive, setIsActive] = useState(!!menuIsOpen)
42
- const menuStyle = getSelectStyle({ name: 'menu', usePrefixes: true })
44
+ const menuStyle = getSelectStyle({ name: 'menu' })
43
45
 
44
46
  // Expose the setIsActive function to the parent component
45
47
  useImperativeHandle(ref, () => ({ setIsActive }))
@@ -106,9 +108,9 @@ export const Dropdown = forwardRef(function Dropdown({
106
108
  }
107
109
  <ul
108
110
  style={{ minWidth }}
109
- class={`${menuStyle} absolute invisible opacity-0 select-none min-w-full z-[1]`}
111
+ class={`${menuStyle} absolute invisible opacity-0 select-none min-w-full z-[1] ${menuClassName}`}
110
112
  >
111
- {menuChildren}
113
+ {menuContent}
112
114
  {
113
115
  options && options.map((option, i) => {
114
116
  const optionStyle = getSelectStyle({ name: 'option', usePrefixes: true, isSelected: option.isSelected })
@@ -131,10 +133,12 @@ export const Dropdown = forwardRef(function Dropdown({
131
133
  })
132
134
 
133
135
  const style = css`
134
- ul {
136
+ &>ul {
135
137
  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;
136
138
  max-width: 0; // handy if the dropdown ul exceeds the viewport width
137
139
  max-height: 0; // handy if the dropdown ul exceeds the viewport height
140
+ /* overflow: visible !important; // override menustyle */
141
+ pointer-events: none;
138
142
  }
139
143
  &.is-bottom-right,
140
144
  &.is-top-right {
@@ -145,14 +149,14 @@ const style = css`
145
149
  }
146
150
  &.is-bottom-left,
147
151
  &.is-bottom-right {
148
- ul {
152
+ &>ul {
149
153
  top: 100%;
150
154
  transform: translateY(6px);
151
155
  }
152
156
  }
153
157
  &.is-top-left,
154
158
  &.is-top-right {
155
- ul {
159
+ &>ul {
156
160
  bottom: 100%;
157
161
  transform: translateY(-10px);
158
162
  }
@@ -161,15 +165,17 @@ const style = css`
161
165
  &.is-hoverable:hover,
162
166
  &:focus,
163
167
  &.is-active,
164
- li:hover,
165
- li:focus,
166
- li.is-active {
167
- ul {
168
+ &>ul>li:hover,
169
+ &>ul>li:focus,
170
+ &>ul>li.is-active {
171
+ &>ul {
168
172
  opacity: 1;
169
173
  visibility: visible;
170
174
  transition: transform 0.15s ease, opacity 0.15s ease;
171
175
  max-width: 1000px;
172
176
  max-height: 1000px;
177
+ pointer-events: auto;
178
+ overflow: visible;
173
179
  }
174
180
  &.is-bottom-left > ul,
175
181
  &.is-bottom-right > ul {
@@ -182,7 +188,7 @@ const style = css`
182
188
  }
183
189
  // no animation
184
190
  &.no-animation {
185
- ul {
191
+ &>ul {
186
192
  transition: none;
187
193
  }
188
194
  }
@@ -0,0 +1,183 @@
1
+ import { forwardRef, Dispatch, SetStateAction, useRef, useEffect, useImperativeHandle } from 'react'
2
+ import { Button, Dropdown, Field, Select, twMerge } from 'nitro-web'
3
+ import { camelCaseToTitle, debounce, omit, queryString, queryObject } from 'nitro-web/util'
4
+ import { ListFilterIcon } from 'lucide-react'
5
+
6
+ export type FilterType = {
7
+ name: string
8
+ type: 'text'|'date'|'search'|'select'
9
+ label?: string
10
+ enums?: { label: string, value: string }[]
11
+ placeholder?: string
12
+ }
13
+
14
+ type FilterState = {
15
+ [key: string]: string | true
16
+ }
17
+
18
+ type FiltersProps = {
19
+ filters?: FilterType[]
20
+ state: FilterState
21
+ setState: Dispatch<SetStateAction<FilterState>>
22
+ elements?: {
23
+ Button?: typeof Button
24
+ Dropdown?: typeof Dropdown
25
+ Field?: typeof Field
26
+ Select?: typeof Select
27
+ FilterIcon?: typeof ListFilterIcon
28
+ }
29
+ dropdownProps?: Partial<React.ComponentProps<typeof Dropdown>>
30
+ buttonProps?: Partial<React.ComponentProps<typeof Button>>
31
+ buttonClassName?: string
32
+ buttonText?: string
33
+ buttonCounterClassName?: string
34
+ }
35
+
36
+ export type FiltersHandleType = {
37
+ submit: (includePagination?: boolean) => void
38
+ }
39
+
40
+ export const Filters = forwardRef<FiltersHandleType, FiltersProps>(({
41
+ filters, state, setState, elements, dropdownProps, buttonProps, buttonClassName, buttonText, buttonCounterClassName,
42
+ }, ref) => {
43
+ const location = useLocation()
44
+ const stateRef = useRef(state)
45
+ const [debouncedSubmit] = useState(() => debounce(submit, 150))
46
+ const count = Object.keys(state).length - (Object.keys(state).includes('page') ? 1 : 0)
47
+ const Elements = {
48
+ Button: elements?.Button || Button,
49
+ Dropdown: elements?.Dropdown || Dropdown,
50
+ Field: elements?.Field || Field,
51
+ Select: elements?.Select || Select,
52
+ FilterIcon: elements?.FilterIcon || ListFilterIcon,
53
+ }
54
+
55
+ useImperativeHandle(ref, () => ({
56
+ submit: debouncedSubmit,
57
+ }))
58
+
59
+ useEffect(() => {
60
+ return () => debouncedSubmit.cancel()
61
+ }, [])
62
+
63
+ useEffect(() => {
64
+ stateRef.current = state
65
+ }, [state])
66
+
67
+ useEffect(() => {
68
+ setState(() => ({
69
+ ...queryObject(location.search),
70
+ }))
71
+ }, [location.search])
72
+
73
+ function reset(e: React.MouseEvent<HTMLAnchorElement>, filter: FilterType) {
74
+ e.preventDefault()
75
+ setState((s) => omit(s, [filter.name]) as FilterState)
76
+ debouncedSubmit()
77
+ }
78
+
79
+ function resetAll(e: React.MouseEvent<HTMLButtonElement>) {
80
+ e.preventDefault()
81
+ setState((s) => ({
82
+ ...(s.page ? { page: s.page } : {}), // keep pagination
83
+ } as FilterState))
84
+ debouncedSubmit()
85
+ }
86
+
87
+ async function _onChange(e: {target: {id: string, value: unknown}}) {
88
+ await onChange(setState, e)
89
+ debouncedSubmit()
90
+ }
91
+
92
+ // Submit the filters and update the URL
93
+ function submit(includePagination?: boolean) {
94
+ const queryStr = queryString(omit(stateRef.current, includePagination ? [] : ['page']))
95
+ history.pushState(null, '', location.pathname + queryStr)
96
+ }
97
+
98
+ if (!filters) return null
99
+ return (
100
+ <Elements.Dropdown
101
+ dir="bottom-right"
102
+ // menuIsOpen={true}
103
+ menuClassName="!rounded-lg"
104
+ menuContent={
105
+ <div class="w-[330px]">
106
+ <div class="flex justify-between items-center border-b p-4 py-3.5">
107
+ <div class="text-lg font-semibold">Filters</div>
108
+ <Button color="clear" size="sm" onClick={resetAll}>Reset All</Button>
109
+ </div>
110
+ <div class="flex flex-col px-4 py-4 mb-[-6px]">
111
+ {
112
+ filters.map((filter) => (
113
+ <div key={filter.name}>
114
+ <div class="flex justify-between">
115
+ <label for={filter.name}>{filter.label || camelCaseToTitle(filter.name)}</label>
116
+ <a href="#" class="label font-normal text-secondary underline" onClick={(e) => reset(e, filter)}>Reset</a>
117
+ </div>
118
+ {
119
+ (filter.type === 'text' || filter.type === 'search') &&
120
+ <Elements.Field
121
+ class="mb-4"
122
+ name={filter.name}
123
+ type={filter.type}
124
+ placeholder={filter.placeholder}
125
+ state={state}
126
+ onChange={_onChange}
127
+ />
128
+ }
129
+ {
130
+ filter.type === 'date' &&
131
+ <Elements.Field
132
+ class="mb-4"
133
+ name={filter.name}
134
+ type="date"
135
+ mode="range"
136
+ state={state}
137
+ onChange={_onChange}
138
+ placeholder={filter.placeholder || 'Select range...'}
139
+ />
140
+ }
141
+ {
142
+ filter.type === 'select' &&
143
+ <Elements.Select
144
+ class="mb-4"
145
+ name={filter.name}
146
+ type="country"
147
+ state={state}
148
+ options={filter.enums || []}
149
+ onChange={_onChange}
150
+ placeholder={filter.placeholder}
151
+ />
152
+ }
153
+ </div>
154
+ ))
155
+ }
156
+ </div>
157
+ </div>
158
+ }
159
+ {...dropdownProps}
160
+ >
161
+ <Elements.Button
162
+ color="white"
163
+ IconLeft={<Elements.FilterIcon size={16} />}
164
+ className={twMerge(`flex gap-x-2.5 ${buttonClassName || ''}`)}
165
+ {...buttonProps}
166
+ >
167
+ <span class="flex items-center gap-x-2.5">
168
+ { buttonText || 'Filter By' }
169
+ {
170
+ !!count &&
171
+ <span
172
+ class={twMerge(`inline-flex items-center justify-center rounded-full text-xs text-white bg-primary w-[19px] h-[19px] ${buttonCounterClassName || ''}`)}
173
+ >
174
+ {count}
175
+ </span>
176
+ }
177
+ </span>
178
+ </Elements.Button>
179
+ </Elements.Dropdown>
180
+ )
181
+ })
182
+
183
+ Filters.displayName = 'Filters'
@@ -26,7 +26,7 @@ export function FieldColor({ defaultColor='#333', Icon, onChange, value, ...prop
26
26
  <Dropdown
27
27
  dir="bottom-left"
28
28
  menuToggles={false}
29
- menuChildren={
29
+ menuContent={
30
30
  <ColorPicker key={lastChanged} defaultColor={defaultColor} id={id} name={props.name} value={value} onChange={onChange} />
31
31
  }
32
32
  >
@@ -44,7 +44,8 @@ export function FieldDate({
44
44
  const dropdownRef = useRef<DropdownRef>(null)
45
45
  const id = props.id || props.name
46
46
  const [month, setMonth] = useState<number|undefined>()
47
-
47
+ const [lastUpdated, setLastUpdated] = useState(0)
48
+
48
49
  // Convert the value to an array of valid* dates
49
50
  const dates = useMemo(() => {
50
51
  const _dates = Array.isArray(value) ? value : [value]
@@ -54,6 +55,11 @@ export function FieldDate({
54
55
  // Hold the input value in state
55
56
  const [inputValue, setInputValue] = useState(() => getInputValue(dates))
56
57
 
58
+ // Update the date's inputValue (text) when the value changes outside of the component
59
+ useEffect(() => {
60
+ if (new Date().getTime() > lastUpdated + 100) setInputValue(getInputValue(dates))
61
+ }, [value])
62
+
57
63
  // Get the prefix content width
58
64
  useEffect(() => {
59
65
  setPrefixWidth(getPrefixWidth(prefix, 4))
@@ -62,7 +68,11 @@ export function FieldDate({
62
68
  function onCalendarChange(mode: Mode, value: null|number|(null|number)[]) {
63
69
  if (mode == 'single' && !showTime) dropdownRef.current?.setIsActive(false) // Close the dropdown
64
70
  setInputValue(getInputValue(value))
65
- if (onChange) onChange({ target: { id: id, value: value as any } })
71
+ // Update the value
72
+ if (onChange) {
73
+ onChange({ target: { id: id, value: value as any } })
74
+ setLastUpdated(new Date().getTime())
75
+ }
66
76
  }
67
77
 
68
78
  function getInputValue(dates: Date|number|null|(Date|number|null)[]) {
@@ -79,7 +89,7 @@ export function FieldDate({
79
89
  })
80
90
 
81
91
  // For single/range we need limit the array
82
- if (mode == 'range') split.length = 2
92
+ if (mode == 'range' && split.length > 1) split.length = 2
83
93
  else if (mode == 'multiple') split = split.filter(o => o) // remove invalid dates
84
94
 
85
95
  // Swap dates if needed
@@ -91,9 +101,12 @@ export function FieldDate({
91
101
  break
92
102
  }
93
103
 
94
- // Update
104
+ // Update the value
95
105
  const value = mode == 'single' ? split[0]?.getTime() ?? null : split.map(d => d?.getTime() ?? null)
96
- if (onChange) onChange({ target: { id: id, value: value as any }})
106
+ if (onChange) {
107
+ onChange({ target: { id: id, value: value as any }})
108
+ setLastUpdated(new Date().getTime())
109
+ }
97
110
  }
98
111
 
99
112
  return (
@@ -103,7 +116,7 @@ export function FieldDate({
103
116
  // animate={false}
104
117
  // menuIsOpen={true}
105
118
  minWidth={0}
106
- menuChildren={
119
+ menuContent={
107
120
  <div className="flex">
108
121
  <Calendar
109
122
  {...{ mode, value, numberOfMonths, month }}
@@ -1,6 +1,6 @@
1
1
  /* eslint-disable @typescript-eslint/no-explicit-any */
2
2
  import { css } from 'twin.macro'
3
- import { util, FieldCurrency, FieldCurrencyProps, FieldColor, FieldColorProps, FieldDate, FieldDateProps } from 'nitro-web'
3
+ import { util, FieldCurrency, FieldCurrencyProps, FieldColor, FieldColorProps, FieldDate, FieldDateProps, twMerge } from 'nitro-web'
4
4
  import { Errors, type Error } from 'nitro-web/types'
5
5
  import {
6
6
  EnvelopeIcon,
@@ -130,7 +130,7 @@ export function Field({ state, icon, iconPos: ip, ...props }: FieldProps) {
130
130
 
131
131
  function FieldContainer({ children, className, error }: { children: React.ReactNode, className?: string, error?: Error }) {
132
132
  return (
133
- <div css={style} className={`mt-2.5 mb-6 mt-input-before mb-input-after grid grid-cols-1 nitro-field ${className || ''}`}>
133
+ <div css={style} className={twMerge(`mt-2.5 mb-6 mt-input-before mb-input-after grid grid-cols-1 nitro-field ${className || ''}`)}>
134
134
  {children}
135
135
  {error && <div class="mt-1.5 text-xs text-danger nitro-error">{error.detail}</div>}
136
136
  </div>
@@ -31,7 +31,7 @@ type SelectProps = {
31
31
  /** The options to display in the dropdown **/
32
32
  options: { value: unknown, label: string | React.ReactNode, fixed?: boolean, [key: string]: unknown }[]
33
33
  /** The state object to get the value and check errors from **/
34
- state?: { errors: Errors, [key: string]: unknown }
34
+ state?: { errors?: Errors, [key: string]: unknown }
35
35
  /** Select variations **/
36
36
  type?: 'country'|'customer'|''
37
37
  /** All other props are passed to react-select **/
@@ -58,7 +58,7 @@ export function Select({ inputId, minMenuWidth, name, prefix='', onChange, optio
58
58
  }
59
59
 
60
60
  return (
61
- <div css={style} class="mt-2.5 mb-6 mt-input-before mb-input-after nitro-select">
61
+ <div css={style} class={twMerge(`mt-2.5 mb-6 mt-input-before mb-input-after nitro-select ${props.className||''}`)}>
62
62
  <ReactSelect
63
63
  /**
64
64
  * react-select prop quick reference (https://react-select.com/props#api):
@@ -1,8 +1,12 @@
1
- import { Drop, Dropdown, Field, Select, Button, Checkbox, GithubLink, Modal, Calendar, injectedConfig } from 'nitro-web'
1
+ import {
2
+ Drop, Dropdown, Field, Select, Button, Checkbox, GithubLink, Modal, Calendar, injectedConfig,
3
+ Filters, FiltersHandleType,
4
+ FilterType,
5
+ } from 'nitro-web'
2
6
  import { getCountryOptions, getCurrencyOptions, ucFirst } from 'nitro-web/util'
3
7
  import { Check } from 'lucide-react'
4
8
 
5
- export function Styleguide() {
9
+ export function Styleguide({ className }: { className?: string }) {
6
10
  const [customerSearch, setCustomerSearch] = useState('')
7
11
  const [showModal1, setShowModal1] = useState(false)
8
12
  const [state, setState] = useState({
@@ -20,6 +24,29 @@ export function Styleguide() {
20
24
  { title: 'address', detail: 'Address is required' },
21
25
  ],
22
26
  })
27
+ const [filterState, setFilterState] = useState({})
28
+ const filtersRef = useRef<FiltersHandleType>(null)
29
+ const filters: FilterType[] = [
30
+ {
31
+ name: 'dateRange',
32
+ type: 'date',
33
+ },
34
+ {
35
+ name: 'search',
36
+ type: 'search',
37
+ label: 'Keyword Search',
38
+ placeholder: 'Job, employee name...',
39
+ },
40
+ {
41
+ name: 'status',
42
+ type: 'select',
43
+ enums: [
44
+ { label: 'Pending', value: 'pending' },
45
+ { label: 'Approved', value: 'approved' },
46
+ { label: 'Rejected', value: 'rejected' },
47
+ ],
48
+ },
49
+ ]
23
50
 
24
51
  // Example of updating state
25
52
  // useEffect(() => {
@@ -52,7 +79,7 @@ export function Styleguide() {
52
79
  }
53
80
 
54
81
  return (
55
- <div class="mb-10 text-left max-w-[1100px]">
82
+ <div class={`text-left max-w-[1100px] ${className}`}>
56
83
  <GithubLink filename={__filename} />
57
84
  <div class="mb-7">
58
85
  <h1 class="h1">{injectedConfig.isDemo ? 'Design System' : 'Style Guide'}</h1>
@@ -98,6 +125,31 @@ export function Styleguide() {
98
125
  </div>
99
126
  </div>
100
127
 
128
+ <h2 class="h3">Filters</h2>
129
+ <div class="flex flex-wrap gap-x-6 gap-y-4 mb-10">
130
+ {/* Filter dropdown */}
131
+ <Filters
132
+ ref={filtersRef}
133
+ filters={filters}
134
+ state={filterState}
135
+ setState={setFilterState}
136
+ dropdownProps={{ dir: 'bottom-left' }}
137
+ />
138
+ {/* Search bar */}
139
+ <Field
140
+ class="!my-0 min-w-[242px]"
141
+ type="search"
142
+ name="search"
143
+ iconPos="left"
144
+ state={filterState}
145
+ onChange={(e) => {
146
+ onChange(setFilterState, e)
147
+ filtersRef.current?.submit()
148
+ }}
149
+ placeholder="Linked search bar..."
150
+ />
151
+ </div>
152
+
101
153
  <h2 class="h3">Buttons</h2>
102
154
  <div class="flex flex-wrap gap-x-6 gap-y-4 mb-10">
103
155
  <div><Button color="primary">primary (default)</Button></div>
@@ -273,7 +325,7 @@ export function Styleguide() {
273
325
  </div>
274
326
 
275
327
  <h2 class="h3">File Inputs & Calendar</h2>
276
- <div class="grid grid-cols-3 gap-x-6 mb-4">
328
+ <div class="grid grid-cols-3 gap-x-6">
277
329
  <div>
278
330
  <label for="avatar">Avatar</label>
279
331
  <Drop class="is-small" name="avatar" state={state} onChange={(e) => onChange(setState, e)} awsUrl={injectedConfig.awsUrl} />
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "nitro-web",
3
- "version": "0.0.47",
3
+ "version": "0.0.49",
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/types/util.d.ts CHANGED
@@ -117,30 +117,31 @@ export function currencyToCents(currency: string): string;
117
117
  */
118
118
  export function date(date: number | Date, format?: string, timezone?: string): string;
119
119
  /**
120
+ * @template {(...args: any[]) => any} T
120
121
  * Creates a debounced function that delays invoking `func` until after `wait`
121
122
  * milliseconds have elapsed since the last time the debounced function was invoked.
122
123
  *
123
- * @param {Function} func - The function to debounce.
124
+ * @param {T} func - The function to debounce.
124
125
  * @param {number} [wait=0] - Number of milliseconds to delay.
125
126
  * @param {{
126
127
  * leading?: boolean, // invoke on the leading edge of the timeout (default: false)
127
128
  * maxWait?: number, // maximum time `func` is allowed to be delayed before it's invoked
128
129
  * trailing?: boolean, // invoke on the trailing edge of the timeout (default: true)
129
130
  * }} [options] - Options to control behavior.
130
- * @returns {(...args: any[]) => any & {
131
- * cancel: () => void,
132
- * flush: () => any
133
- * }} - A new debounced function with `cancel` and `flush` methods.
131
+ * @returns {((...args: Parameters<T>) => ReturnType<T>) & {
132
+ * cancel: () => void;
133
+ * flush: () => ReturnType<T>
134
+ * }}
134
135
  *
135
136
  * @see https://lodash.com/docs/4.17.15#debounce
136
137
  */
137
- export function debounce(func: Function, wait?: number, options?: {
138
+ export function debounce<T extends (...args: any[]) => any>(func: T, wait?: number, options?: {
138
139
  leading?: boolean;
139
140
  maxWait?: number;
140
141
  trailing?: boolean;
141
- }): (...args: any[]) => any & {
142
+ }): ((...args: Parameters<T>) => ReturnType<T>) & {
142
143
  cancel: () => void;
143
- flush: () => any;
144
+ flush: () => ReturnType<T>;
144
145
  };
145
146
  /**
146
147
  * Deep clones an object or array, preserving its type
@@ -508,6 +509,12 @@ export function pick(obj: {
508
509
  export function queryObject(searchString: string, trueDefaults?: boolean): {
509
510
  [key: string]: string | true;
510
511
  };
512
+ /**
513
+ * Parses a query string into an array of objects
514
+ * @param {string} searchString - location.search or location.href, e.g. '?page=1', 'https://...co.nz?page=1'
515
+ * @returns {object[]} - e.g. [{ page: '1' }]
516
+ */
517
+ export function queryArray(searchString: string): object[];
511
518
  /**
512
519
  * Parses an object and returns a query string
513
520
  * @param {{[key: string]: unknown}} [obj] - query object
@@ -595,7 +602,7 @@ export function sortByKey(collection: {
595
602
  }[], key: string): object[];
596
603
  /**
597
604
  * Creates a throttled function that only invokes `func` at most once per every `wait` milliseconds
598
- * @param {function} func
605
+ * @param {(...args: any[]) => any} func
599
606
  * @param {number} [wait=0] - the number of milliseconds to throttle invocations to
600
607
  * @param {{
601
608
  * leading?: boolean, // invoke on the leading edge of the timeout
@@ -605,7 +612,7 @@ export function sortByKey(collection: {
605
612
  * @example const throttled = util.throttle(updatePosition, 100)
606
613
  * @see lodash
607
614
  */
608
- export function throttle(func: Function, wait?: number, options?: {
615
+ export function throttle(func: (...args: any[]) => any, wait?: number, options?: {
609
616
  leading?: boolean;
610
617
  trailing?: boolean;
611
618
  }): Function;
@@ -1 +1 @@
1
- {"version":3,"file":"util.d.ts","sourceRoot":"","sources":["../util.js"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"util.d.ts","sourceRoot":"","sources":["../util.js"],"names":[],"mappings":"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"}
package/util.js CHANGED
@@ -175,7 +175,7 @@ export function currencyToCents (currency) {
175
175
  * return unexpected result (it may ignore daylight saving).
176
176
  */
177
177
  export function date (date, format, timezone) {
178
- if (!date || (!isNumber(date) && !isDate(date))) return 'Date?'
178
+ if (!date) return 'Date?'
179
179
 
180
180
  // Get the milliseconds
181
181
  let milliseconds = 0
@@ -192,20 +192,21 @@ export function date (date, format, timezone) {
192
192
  }
193
193
 
194
194
  /**
195
+ * @template {(...args: any[]) => any} T
195
196
  * Creates a debounced function that delays invoking `func` until after `wait`
196
197
  * milliseconds have elapsed since the last time the debounced function was invoked.
197
198
  *
198
- * @param {Function} func - The function to debounce.
199
+ * @param {T} func - The function to debounce.
199
200
  * @param {number} [wait=0] - Number of milliseconds to delay.
200
201
  * @param {{
201
202
  * leading?: boolean, // invoke on the leading edge of the timeout (default: false)
202
203
  * maxWait?: number, // maximum time `func` is allowed to be delayed before it's invoked
203
204
  * trailing?: boolean, // invoke on the trailing edge of the timeout (default: true)
204
205
  * }} [options] - Options to control behavior.
205
- * @returns {(...args: any[]) => any & {
206
- * cancel: () => void,
207
- * flush: () => any
208
- * }} - A new debounced function with `cancel` and `flush` methods.
206
+ * @returns {((...args: Parameters<T>) => ReturnType<T>) & {
207
+ * cancel: () => void;
208
+ * flush: () => ReturnType<T>
209
+ * }}
209
210
  *
210
211
  * @see https://lodash.com/docs/4.17.15#debounce
211
212
  */
@@ -1245,6 +1246,18 @@ export function queryObject (searchString, trueDefaults) {
1245
1246
  return obj
1246
1247
  }
1247
1248
 
1249
+ /**
1250
+ * Parses a query string into an array of objects
1251
+ * @param {string} searchString - location.search or location.href, e.g. '?page=1', 'https://...co.nz?page=1'
1252
+ * @returns {object[]} - e.g. [{ page: '1' }]
1253
+ */
1254
+ export function queryArray (searchString) {
1255
+ const query = queryObject(searchString)
1256
+ return Object.keys(query).map((key) => {
1257
+ return { [key]: query[key] }
1258
+ })
1259
+ }
1260
+
1248
1261
  /**
1249
1262
  * Parses an object and returns a query string
1250
1263
  * @param {{[key: string]: unknown}} [obj] - query object
@@ -1489,7 +1502,7 @@ export function sortByKey (collection, key) {
1489
1502
 
1490
1503
  /**
1491
1504
  * Creates a throttled function that only invokes `func` at most once per every `wait` milliseconds
1492
- * @param {function} func
1505
+ * @param {(...args: any[]) => any} func
1493
1506
  * @param {number} [wait=0] - the number of milliseconds to throttle invocations to
1494
1507
  * @param {{
1495
1508
  * leading?: boolean, // invoke on the leading edge of the timeout