nitro-web 0.0.72 → 0.0.74

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/app.tsx CHANGED
@@ -1,4 +1,4 @@
1
- import { createBrowserRouter, createHashRouter, redirect, useParams, RouterProvider } from 'react-router-dom'
1
+ import { createBrowserRouter, createHashRouter, redirect, RouterProvider } from 'react-router-dom'
2
2
  import { Fragment, ReactNode } from 'react'
3
3
  import ReactDOM from 'react-dom/client'
4
4
  import { axios, camelCase, pick, toArray, setTimeoutPromise } from 'nitro-web/util'
@@ -25,7 +25,7 @@ type Settings = {
25
25
  }
26
26
 
27
27
  type Route = {
28
- component: React.FC<{ route?: Route; params?: object; location?: object; config?: Config }>
28
+ component: React.FC<{ route?: Route; config?: Config }>
29
29
  middleware: string[]
30
30
  name: string
31
31
  path: string
@@ -70,9 +70,7 @@ export function updateJwt(token?: string | null) {
70
70
  }
71
71
 
72
72
  function App({ settings, config, storeContainer }: { settings: Settings, config: Config, storeContainer: StoreContainer }): ReactNode {
73
- // const themeNormalised = theme
74
- const router = getRouter({ settings, config })
75
- // const theme = pick(themeNormalised, []) // e.g. 'topPanelHeight'
73
+ const router = useMemo(() => getRouter({ settings, config }), [])
76
74
 
77
75
  useEffect(() => {
78
76
  /**
@@ -97,10 +95,8 @@ function App({ settings, config, storeContainer }: { settings: Settings, config:
97
95
 
98
96
  return (
99
97
  <storeContainer.Provider>
100
- {/* <ThemeProvider theme={themeNormalised}> */}
101
- { router && <RouterProvider router={router} /> }
98
+ { router && <RouterProvider router={router}/> }
102
99
  <AfterApp settings={settings} />
103
- {/* </ThemeProvider> */}
104
100
  </storeContainer.Provider>
105
101
  )
106
102
  }
@@ -206,7 +202,7 @@ function getRouter({ settings, config }: { settings: Settings, config: Config })
206
202
  ),
207
203
  path: route.path,
208
204
  loader: async () => { // request
209
- // wait for container/exposedStoreData to be setup
205
+ // wait for container/exposedStoreData to be setup (note that this causes ReactRouter to re-render, but not the page)
210
206
  if (!nonce) {
211
207
  nonce = true
212
208
  await setTimeoutPromise(() => {}, 0)
@@ -255,11 +251,9 @@ function RestoreScroll() {
255
251
 
256
252
  function RouteComponent({ route, config }: { route: Route, config: Config }) {
257
253
  const Component = route.component
258
- const params = useParams()
259
- const location = useLocation()
260
254
  document.title = route.meta?.title || ''
261
255
  return (
262
- <Component route={route} params={params} location={location} config={config} />
256
+ <Component route={route} config={config} />
263
257
  )
264
258
  }
265
259
 
@@ -1,10 +1,11 @@
1
1
  import { twMerge } from 'nitro-web'
2
2
  import { ChevronDown, ChevronUp } from 'lucide-react'
3
3
 
4
- type Button = React.ButtonHTMLAttributes<HTMLButtonElement> & {
4
+ interface Button extends React.ButtonHTMLAttributes<HTMLButtonElement> {
5
5
  color?: 'primary'|'secondary'|'black'|'dark'|'white'|'clear'|'custom'
6
- size?: 'xs'|'sm'|'md'|'lg'
6
+ size?: 'xs'|'sm'|'md'|'lg'|'custom'
7
7
  customColor?: string
8
+ customSize?: string
8
9
  className?: string
9
10
  isLoading?: boolean
10
11
  IconLeft?: React.ReactNode|'v'
@@ -19,6 +20,7 @@ export function Button({
19
20
  size='md',
20
21
  color='primary',
21
22
  customColor,
23
+ customSize,
22
24
  className,
23
25
  isLoading,
24
26
  IconLeft,
@@ -49,26 +51,27 @@ export function Button({
49
51
 
50
52
  // Button sizes (px is better for height consistency)
51
53
  const sizes = {
52
- xs: 'px-[6px] h-[25px] px-button-x-xs h-button-h-xs text-xs !text-button-xs rounded',
53
- sm: 'px-[10px] h-[32px] px-button-x-sm h-button-h-sm text-button-md text-button-sm rounded-md',
54
- md: 'px-[12px] h-[38px] px-button-x-md h-button-h-md text-button-md rounded-md', // default
55
- lg: 'px-[18px] h-[42px] px-button-x-lg h-button-h-lg text-button-md !text-button-lg rounded-md',
54
+ 'xs': 'px-[6px] h-[25px] text-xs !text-button-xs rounded',
55
+ 'sm': 'px-[10px] h-[32px] text-md text-button-base rounded-md',
56
+ 'md': 'px-[12px] h-[38px] text-md text-button-base rounded-md', // default
57
+ 'lg': 'px-[18px] h-[42px] text-md text-button-base rounded-md',
56
58
  }
57
59
 
58
60
  const appliedColor = color === 'custom' ? customColor : colors[color]
61
+ const appliedSize = size === 'custom' ? customSize : sizes[size]
59
62
  const contentLayout = `gap-x-1.5 ${iconPosition == 'none' ? '' : ''}`
60
63
  const loading = isLoading ? '[&>*]:opacity-0 text-opacity-0' : ''
61
64
 
62
65
  function getIcon(Icon: React.ReactNode | 'v') {
63
- if (Icon == 'v' || Icon == 'down') return <ChevronDown size={16.5} className="mt-[-1.4rem] mb-[-1.5rem] -mx-0.5" />
64
- if (Icon == '^' || Icon == 'up') return <ChevronUp size={16.5} className="mt-[-1.4rem] mb-[-1.5rem] -mx-0.5" />
66
+ if (Icon == 'v' || Icon == 'down') return <ChevronDown size={16.5} className="mt-[-1.4rem] mb-[-1.5rem]" />
67
+ if (Icon == '^' || Icon == 'up') return <ChevronUp size={16.5} className="mt-[-1.4rem] mb-[-1.5rem]" />
65
68
  else return Icon
66
69
  }
67
70
 
68
71
  return (
69
72
  <button
70
73
  type={type}
71
- class={twMerge(`${base} ${sizes[size]} ${appliedColor} ${contentLayout} ${loading} nitro-button ${className||''}`)}
74
+ class={twMerge(`${base} ${appliedSize} ${appliedColor} ${contentLayout} ${loading} nitro-button ${className||''}`)}
72
75
  {...props}
73
76
  >
74
77
  {
@@ -3,6 +3,8 @@ import { isValid } from 'date-fns'
3
3
  import 'react-day-picker/style.css'
4
4
  import { IsFirstRender } from 'nitro-web'
5
5
 
6
+ export const dayButtonClassName = 'size-[33px] text-sm'
7
+
6
8
  type Mode = 'single'|'multiple'|'range'
7
9
  type ModeSelection<T extends Mode> = (
8
10
  T extends 'single' ? Date | undefined
@@ -94,7 +96,7 @@ export function Calendar({ mode='single', onChange, value, numberOfMonths, month
94
96
  // Days
95
97
  weekday: `${d.weekday} text-[11px] font-bold uppercase`,
96
98
  day: `${d.day} size-[33px]`,
97
- day_button: `${d.day_button} size-[33px] text-sm`,
99
+ day_button: `${d.day_button} ${dayButtonClassName}`,
98
100
 
99
101
  // States
100
102
  focused: `${d.focused} [&>button]:bg-gray-200 [&>button]:border-gray-200`,
@@ -14,14 +14,14 @@ type DropdownProps = {
14
14
  options?: { label: string|React.ReactNode, onClick?: Function, isSelected?: boolean, icon?: React.ReactNode, className?: string }[]
15
15
  /** Whether the dropdown is hoverable **/
16
16
  isHoverable?: boolean
17
- /** The minimum width of the menu **/
18
- minWidth?: number | string
19
17
  /** The content to render inside the top of the dropdown **/
20
18
  menuContent?: React.ReactNode
21
19
  menuClassName?: string
22
20
  menuOptionClassName?: string
23
21
  menuIsOpen?: boolean
24
22
  menuToggles?: boolean
23
+ /** The minimum width of the menu **/
24
+ minWidth?: number | string
25
25
  toggleCallback?: (isActive: boolean) => void
26
26
  }
27
27
 
@@ -30,15 +30,15 @@ export const Dropdown = forwardRef(function Dropdown({
30
30
  animate=true,
31
31
  children,
32
32
  className,
33
- dir,
33
+ dir='bottom-left',
34
34
  options,
35
35
  isHoverable,
36
- minWidth, // remove in favour of menuClassName
37
36
  menuClassName,
38
37
  menuOptionClassName,
39
38
  menuContent,
40
39
  menuIsOpen,
41
40
  menuToggles=true,
41
+ minWidth,
42
42
  toggleCallback,
43
43
  }: DropdownProps, ref) {
44
44
  // https://letsbuildui.dev/articles/building-a-dropdown-menu-component-with-react-hooks
@@ -46,6 +46,8 @@ export const Dropdown = forwardRef(function Dropdown({
46
46
  const dropdownRef = useRef<HTMLDivElement|null>(null)
47
47
  const [isActive, setIsActive] = useState(!!menuIsOpen)
48
48
  const menuStyle = getSelectStyle({ name: 'menu' })
49
+ const [direction, setDirection] = useState<null | 'bottom-left' | 'bottom-right' | 'top-left' | 'top-right'>(null)
50
+ const [ready, setReady] = useState(false)
49
51
 
50
52
  // Expose the setIsActive function to the parent component
51
53
  useImperativeHandle(ref, () => ({ setIsActive }))
@@ -76,7 +78,50 @@ export const Dropdown = forwardRef(function Dropdown({
76
78
  useEffect(() => {
77
79
  if (toggleCallback) toggleCallback(isActive)
78
80
  }, [isActive])
81
+
82
+ useEffect(() => {
83
+ setReady(false)
84
+ if (!isActive || !dropdownRef.current) return
85
+
86
+ const ul = dropdownRef.current.querySelector('ul') as HTMLElement
87
+ if (!ul) return
88
+
89
+ // Temporarily show the ul for measurement
90
+ const originalMaxHeight = ul.style.maxHeight
91
+ const originalVisibility = ul.style.visibility
92
+ const originalOpacity = ul.style.opacity
93
+ const originalPointerEvents = ul.style.pointerEvents
94
+
95
+ ul.style.maxHeight = 'none'
96
+ ul.style.visibility = 'hidden'
97
+ ul.style.opacity = '0'
98
+ ul.style.pointerEvents = 'none'
79
99
 
100
+ const dropdownHeight = ul.getBoundingClientRect().height
101
+
102
+ // Revert styles
103
+ ul.style.maxHeight = originalMaxHeight
104
+ ul.style.visibility = originalVisibility
105
+ ul.style.opacity = originalOpacity
106
+ ul.style.pointerEvents = originalPointerEvents
107
+
108
+ const rect = dropdownRef.current.getBoundingClientRect()
109
+ const spaceBelow = window.innerHeight - rect.bottom
110
+ const spaceAbove = rect.top
111
+
112
+ const side = dir.endsWith('right') ? 'right' : 'left'
113
+
114
+ const newDirection = dir.startsWith('bottom')
115
+ ? `${spaceBelow < dropdownHeight && spaceAbove > dropdownHeight ? 'top' : 'bottom'}-${side}`
116
+ : `${spaceAbove < dropdownHeight && spaceBelow > dropdownHeight ? 'bottom' : 'top'}-${side}`
117
+
118
+ setDirection(newDirection as 'bottom-left' | 'bottom-right' | 'top-left' | 'top-right')
119
+
120
+ requestAnimationFrame(() => {
121
+ setReady(true)
122
+ })
123
+ }, [isActive, dir])
124
+
80
125
  function onMouseDown(e: { key: string, preventDefault: Function }) {
81
126
  if (e.key && e.key != 'Enter') return
82
127
  if (e.key) e.preventDefault() // for button, stops buttons firing twice
@@ -87,12 +132,13 @@ export const Dropdown = forwardRef(function Dropdown({
87
132
  if (option.onClick) option.onClick(e)
88
133
  if (!menuIsOpen) setIsActive(!isActive)
89
134
  }
135
+ var ready2
90
136
 
91
137
  return (
92
138
  <div
93
139
  class={
94
- 'relative' +
95
- (dir ? ` is-${dir}` : ' is-bottom-left') +
140
+ `relative is-${direction || dir}` + // until hovered, show the original direction to prevent scrollbars
141
+ (ready2 ? ' is-ready' : '') +
96
142
  (isHoverable ? ' is-hoverable' : '') +
97
143
  (isActive ? ' is-active' : '') +
98
144
  (!animate ? ' no-animation' : '') +
@@ -113,7 +159,8 @@ export const Dropdown = forwardRef(function Dropdown({
113
159
  }
114
160
  <ul
115
161
  style={{ minWidth }}
116
- class={twMerge(`${menuStyle} absolute invisible opacity-0 select-none min-w-full z-[1] ${menuClassName}`)}
162
+ class={
163
+ twMerge(`${menuStyle} ${ready ? 'is-ready' : ''} absolute invisible opacity-0 select-none min-w-full z-[1] ${menuClassName||''}`)}
117
164
  >
118
165
  {menuContent}
119
166
  {
@@ -127,7 +174,7 @@ export const Dropdown = forwardRef(function Dropdown({
127
174
  >
128
175
  <span class="flex-auto">{option.label}</span>
129
176
  { !!option.icon && option.icon }
130
- { option.isSelected && <CheckCircleIcon className="size-[22px] text-primary -my-1 -mx-1" /> }
177
+ { option.isSelected && <CheckCircleIcon className="size-[22px] text-primary -my-1 -mx-0.5" /> }
131
178
  </li>
132
179
  )
133
180
  })
@@ -172,7 +219,7 @@ const style = css`
172
219
  &>ul>li:hover,
173
220
  &>ul>li:focus,
174
221
  &>ul>li.is-active {
175
- &>ul {
222
+ &>ul.is-ready {
176
223
  opacity: 1;
177
224
  visibility: visible;
178
225
  transition: transform 0.15s ease, opacity 0.15s ease;
@@ -123,7 +123,7 @@ export const Filters = forwardRef<FiltersHandleType, FiltersProps>(({
123
123
  allowOverflow={true}
124
124
  // menuIsOpen={true}
125
125
  {...dropdownProps}
126
- menuClassName={twMerge(`!rounded-lg min-w-[330px] ${dropdownProps?.menuClassName || ''}`)}
126
+ menuClassName={twMerge(`min-w-[330px] ${dropdownProps?.menuClassName || ''}`)}
127
127
  menuContent={
128
128
  <div>
129
129
  <div class="flex justify-between items-center border-b p-4 py-3.5">
@@ -146,7 +146,7 @@ export const Filters = forwardRef<FiltersHandleType, FiltersProps>(({
146
146
  filter.type === 'select' &&
147
147
  <Elements.Select
148
148
  {...filter}
149
- class="mb-0"
149
+ class="!mb-0"
150
150
  state={state}
151
151
  onChange={onInputChange}
152
152
  type={undefined}
@@ -156,7 +156,7 @@ export const Filters = forwardRef<FiltersHandleType, FiltersProps>(({
156
156
  filter.type !== 'select' &&
157
157
  <Elements.Field
158
158
  {...filter}
159
- class="mb-0"
159
+ class="!mb-0"
160
160
  state={state}
161
161
  onChange={onInputChange}
162
162
  />
@@ -1,7 +1,7 @@
1
1
  import GithubIcon from 'nitro-web/client/imgs/github.svg'
2
2
 
3
3
  export function GithubLink({ filename }: { filename: string }) {
4
- const base = 'https://github.com/boycce/nitro-web/blob/master/'
4
+ const base = 'https://github.com/boycce/nitro-web/blob/master/packages/'
5
5
  // Filenames are relative to the webpack start directory
6
6
  // 1. Remove ../ from filename (i.e. for _example build)
7
7
  // 2. Remove node_modules/nitro-web/ from filename (i.e. for packages using nitro-web)
@@ -6,10 +6,10 @@ import {
6
6
  Bars3Icon,
7
7
  HomeIcon,
8
8
  UsersIcon,
9
- XMarkIcon,
10
9
  ArrowLeftCircleIcon,
11
10
  PaintBrushIcon,
12
11
  } from '@heroicons/react/24/outline'
12
+ import { XIcon } from 'lucide-react'
13
13
 
14
14
  const sidebarWidth = 'w-80'
15
15
 
@@ -42,7 +42,7 @@ export function Sidebar({ Logo, menu, links }: SidebarProps) {
42
42
  (sidebarOpen ? 'opacity-100' : 'opacity-0')
43
43
  }>
44
44
  <button type="button" onClick={() => setSidebarOpen(false)} className="-m-2.5 p-2.5">
45
- <XMarkIcon aria-hidden="true" className="size-6 text-white" />
45
+ <XIcon aria-hidden="true" strokeWidth={1.5} size={24} className="text-white" />
46
46
  </button>
47
47
  </div>
48
48
  <SidebarContents Logo={Logo} menu={menu} links={links} />
@@ -1,119 +1,146 @@
1
- type CheckboxProps = {
1
+ /* eslint-disable @typescript-eslint/no-explicit-any */
2
+ import { twMerge, deepFind, getErrorFromState } from 'nitro-web/util'
3
+ import { Errors, type Error } from 'nitro-web/types'
4
+
5
+ type CheckboxProps = React.InputHTMLAttributes<HTMLInputElement> & {
6
+ /** field name or path on state (used to match errors), e.g. 'date', 'company.email' */
2
7
  name: string
3
- /** name is applied if not provided. Used for radios */
8
+ /** name is applied if id is not provided. Used for radios */
4
9
  id?: string
5
- size?: 'md' | 'sm'
10
+ /** state object to get the value, and check errors against */
11
+ state?: { errors?: Errors, [key: string]: any }
12
+ size?: number
6
13
  subtext?: string|React.ReactNode
7
14
  text?: string|React.ReactNode
8
15
  type?: 'checkbox' | 'radio' | 'toggle'
9
- [key: string]: unknown
16
+ checkboxClassName?: string
17
+ svgClassName?: string
18
+ labelClassName?: string
10
19
  }
11
20
 
12
- export function Checkbox({ name, id, size='sm', subtext, text, type='checkbox', ...props }: CheckboxProps) {
21
+ export function Checkbox({
22
+ state, size, subtext, text, type='checkbox', className, checkboxClassName, svgClassName, labelClassName, ...props
23
+ }: CheckboxProps) {
13
24
  // Checkbox/radio/toggle component
14
- // https://tailwindui.com/components/application-ui/forms/checkboxes#component-744ed4fa65ba36b925701eb4da5c6e31
15
- if (!name) throw new Error('Checkbox requires a `name` prop')
16
- id = id || name
25
+ let value!: boolean
26
+ const error = getErrorFromState(state, props.name)
27
+ const id = props.id || props.name
17
28
 
18
- const sizeMap = {
19
- sm: {
20
- checkbox: 'size-[14px]',
21
- toggleWidth: 'w-[32px]', // 4px border + (toggleAfterSize * 2)
22
- toggleHeight: 'h-[18px]',
23
- toggleAfterSize: 'after:size-[14px]', // account for 2px border
24
- },
25
- md: {
26
- checkbox: 'size-[16px]',
27
- toggleWidth: 'w-[40px]', // 4px border + (toggleAfterSize * 2)
28
- toggleHeight: 'h-[22px]',
29
- toggleAfterSize: 'after:size-[18px]', // account for 2px border
30
- },
29
+ if (!props.name) throw new Error('Checkbox requires a `name` prop')
30
+
31
+ // Value: Input is always controlled if state is passed in
32
+ if (typeof props.checked !== 'undefined') value = props.checked
33
+ else if (typeof state == 'object') {
34
+ const v = deepFind(state, props.name) as boolean | undefined
35
+ value = v ?? false
31
36
  }
32
- const _size = sizeMap[size]
37
+
38
+ const BORDER = 2
39
+ const checkboxSize = size ?? 14
40
+ const toggleHeight = size ?? 18
41
+ const toggleWidth = toggleHeight * 2 - BORDER * 2
42
+ const toggleAfterSize = toggleHeight - BORDER * 2
33
43
 
34
44
  return (
35
- <div className={`mt-2.5 mb-6 mt-input-before mb-input-after flex gap-3 nitro-checkbox ${props.className || ''}`}>
36
- <div className="flex shrink-0 mt-[2px]">
37
- {
38
- type !== 'toggle'
39
- ? <div className={`group grid ${_size.checkbox} grid-cols-1`}>
40
- <input
41
- {...props}
42
- id={id}
43
- name={name}
44
- type={type}
45
- className={
46
- `${type === 'radio' ? 'rounded-full' : 'rounded'} col-start-1 row-start-1 appearance-none border border-gray-300 bg-white focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 disabled:border-gray-300 disabled:bg-gray-100 disabled:checked:bg-gray-100 forced-colors:appearance-auto ` +
47
- // Default
48
- 'checked:border-blue-600 checked:bg-blue-600 indeterminate:border-blue-600 indeterminate:bg-blue-600 focus-visible:outline-blue-600 ' +
49
- // Variable-selected color defined?
50
- 'checked:!border-variable-selected checked:!bg-variable-selected indeterminate:!border-variable-selected indeterminate:!bg-variable-selected focus-visible:!outline-variable-selected'
51
- }
52
- />
53
- <svg
54
- fill="none"
55
- viewBox="0 0 14 14"
56
- className={`pointer-events-none col-start-1 row-start-1 ${_size.checkbox} self-center justify-self-center stroke-white group-has-[:disabled]:stroke-gray-950/25`}
57
- >
58
- {
59
- type === 'radio'
60
- ? <circle
61
- // cx={(_size.checkbox.match(/\d+/)?.[0] as unknown as number) / 2}
62
- // cy={(_size.checkbox.match(/\d+/)?.[0] as unknown as number) / 2}
63
- // r={(_size.checkbox.match(/\d+/)?.[0] as unknown as number) / 6}
64
- cx={7}
65
- cy={7}
66
- r={2.5}
67
- className="fill-white opacity-0 group-has-[:checked]:opacity-100"
68
- />
69
- : <>
70
- <path
71
- d="M4 8L6 10L10 4.5"
72
- strokeWidth={2}
73
- strokeLinecap="round"
74
- strokeLinejoin="round"
75
- className="opacity-0 group-has-[:checked]:opacity-100"
76
- />
77
- <path
78
- d="M4 7H10"
79
- strokeWidth={2}
80
- strokeLinecap="round"
81
- strokeLinejoin="round"
82
- className="opacity-0 group-has-[:indeterminate]:opacity-100"
83
- />
84
- </>
85
- }
86
- </svg>
87
- </div>
88
- : <div className="group grid grid-cols-1">
89
- <input
90
- {...props}
91
- id={id}
92
- name={name}
93
- type="checkbox"
94
- class="sr-only peer"
95
- />
96
- <label
97
- for={id}
98
- className={
99
- `col-start-1 row-start-1 relative ${_size.toggleWidth} ${_size.toggleHeight} bg-gray-200 peer-focus-visible:outline-none peer-focus-visible:ring-4 rounded-full peer peer-checked:after:translate-x-full rtl:peer-checked:after:-translate-x-full peer-checked:after:border-white after:content-[''] after:absolute after:top-[2px] after:start-[2px] after:bg-white after:border-gray-300 after:border after:rounded-full ${_size.toggleAfterSize} after:transition-all ` +
100
- // Default
101
- 'peer-focus-visible:ring-blue-300 peer-checked:bg-blue-600 ' +
102
- // Variable-selected color defined?
103
- 'peer-focus-visible:!ring-variable-selected peer-checked:!bg-variable-selected '
104
- // Dark mode not used yet...
105
- // 'dark:peer-focus-visible:ring-blue-800 dark:bg-gray-700 dark:border-gray-600 '
106
- }
107
- />
108
- </div>
45
+ <div
46
+ className={'mt-2.5 mb-6 ' + twMerge(`mt-input-before mb-input-after text-sm nitro-checkbox ${className}`)}
47
+ >
48
+ <div className="flex gap-3 items-baseline">
49
+ <div className="shrink-0 flex items-center">
50
+ <div className="w-0">&nbsp;</div>
51
+ <div className="group relative">
52
+ {
53
+ type !== 'toggle'
54
+ ? <>
55
+ <input
56
+ {...props}
57
+ type={type}
58
+ style={{ width: checkboxSize, height: checkboxSize }}
59
+ checked={value}
60
+ className={
61
+ twMerge(
62
+ `${type === 'radio' ? 'rounded-full' : 'rounded'} appearance-none border border-gray-300 bg-white forced-colors:appearance-auto disabled:border-gray-300 disabled:bg-gray-100 disabled:checked:bg-gray-100 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 ` +
63
+ // Variable-selected theme colors (was .*-blue-600)
64
+ 'checked:border-variable-selected checked:bg-variable-selected indeterminate:border-variable-selected indeterminate:bg-variable-selected focus-visible:outline-variable-selected ' +
65
+ // Dark mode not used yet... dark:focus-visible:outline-blue-800
66
+ checkboxClassName
67
+ )
68
+ }
69
+ />
70
+ <svg
71
+ fill="none"
72
+ viewBox="0 0 14 14"
73
+ style={{ width: checkboxSize, height: checkboxSize }}
74
+ className={twMerge('absolute top-0 left-0 pointer-events-none justify-self-center stroke-white group-has-[:disabled]:stroke-gray-950/25', svgClassName)}
75
+ >
76
+ {
77
+ type === 'radio'
78
+ ? <circle
79
+ // cx={(_size.checkbox.match(/\d+/)?.[0] as unknown as number) / 2}
80
+ // cy={(_size.checkbox.match(/\d+/)?.[0] as unknown as number) / 2}
81
+ // r={(_size.checkbox.match(/\d+/)?.[0] as unknown as number) / 6}
82
+ cx={7}
83
+ cy={7}
84
+ r={2.5}
85
+ className="fill-white opacity-0 group-has-[:checked]:opacity-100"
86
+ />
87
+ : <>
88
+ <path
89
+ d="M4 8L6 10L10 4.5"
90
+ strokeWidth={2}
91
+ strokeLinecap="round"
92
+ strokeLinejoin="round"
93
+ className="opacity-0 group-has-[:checked]:opacity-100"
94
+ />
95
+ <path
96
+ d="M4 7H10"
97
+ strokeWidth={2}
98
+ strokeLinecap="round"
99
+ strokeLinejoin="round"
100
+ className="opacity-0 group-has-[:indeterminate]:opacity-100"
101
+ />
102
+ </>
103
+ }
104
+ </svg>
105
+ </>
106
+ : <>
107
+ <input
108
+ {...props}
109
+ type="checkbox"
110
+ className="sr-only peer"
111
+ checked={value}
112
+ />
113
+ <label
114
+ for={id}
115
+ style={{ width: toggleWidth, height: toggleHeight }}
116
+ className={
117
+ twMerge(
118
+ 'block bg-gray-200 rounded-full transition-colors peer-focus-visible:outline peer-focus-visible:outline-2 peer-focus-visible:outline-offset-2 ' +
119
+ // Variable-selected theme colors (was .*-blue-600)
120
+ 'peer-checked:bg-variable-selected peer-focus-visible:outline-variable-selected ' +
121
+ labelClassName
122
+ )
123
+ }
124
+ >
125
+ <span
126
+ style={{ width: toggleAfterSize, height: toggleAfterSize }}
127
+ className={
128
+ 'absolute top-[2px] start-[2px] bg-white border-gray-300 border rounded-full transition-all group-has-[:checked]:border-white group-has-[:checked]:translate-x-full '
129
+ }
130
+ />
131
+ </label>
132
+ </>
133
+ }
134
+ </div>
135
+ </div>
136
+ {text &&
137
+ <label for={id} className="text-[length:inherit] leading-[inherit] select-none">
138
+ <span className="text-gray-900">{text}</span>
139
+ <span className="ml-2 text-gray-500">{subtext}</span>
140
+ </label>
109
141
  }
110
142
  </div>
111
- {text &&
112
- <label for={id} className="self-center text-sm select-none">
113
- <span className="text-gray-900">{text}</span>
114
- <span className="ml-2 text-gray-500">{subtext}</span>
115
- </label>
116
- }
143
+ {error && <div class="mt-1.5 text-xs text-danger-foreground nitro-error">{error.detail}</div>}
117
144
  </div>
118
145
  )
119
146
  }
@@ -3,6 +3,7 @@ import { deepFind, s3Image, getErrorFromState } from 'nitro-web/util'
3
3
  import { DropHandler } from 'nitro-web'
4
4
  import noImage from 'nitro-web/client/imgs/no-image.svg'
5
5
  import { Errors, MonasteryImage } from 'nitro-web/types'
6
+ import { twMerge } from 'nitro-web/util'
6
7
 
7
8
  type DropProps = {
8
9
  awsUrl?: string
@@ -93,7 +94,7 @@ export function Drop({ awsUrl, className, id, name, onChange, multiple, state, .
93
94
  // }
94
95
 
95
96
  return (
96
- <div class={`mt-2.5 mb-6 mt-input-before mb-input-after nitro-field nitro-drop ${className || ''}`}>
97
+ <div class={'mt-2.5 mb-6 ' + twMerge(`mt-input-before mb-input-after nitro-field nitro-drop ${className || ''}`)}>
97
98
  <input
98
99
  {...props}
99
100
  id={inputId}
@@ -149,7 +149,7 @@ export function FieldCurrency({ config, currency='nzd', onChange, value, default
149
149
  defaultValue={defaultValue}
150
150
  />
151
151
  <span
152
- class={`absolute top-0 bottom-0 left-3 inline-flex items-center select-none text-gray-500 text-input-base ${dollars !== null && settings.prefix == '$' ? 'text-foreground' : ''}`}
152
+ class={`absolute top-0 bottom-0 left-[12px] left-input-x inline-flex items-center select-none text-gray-500 text-input-base ${dollars !== null && settings.prefix == '$' ? 'text-foreground' : ''}`}
153
153
  >
154
154
  {settings.prefix || settings.suffix}
155
155
  </span>
@@ -2,6 +2,7 @@
2
2
  import { format, isValid, parse } from 'date-fns'
3
3
  import { getPrefixWidth } from 'nitro-web/util'
4
4
  import { Calendar, Dropdown } from 'nitro-web'
5
+ import { dayButtonClassName } from '../element/calendar'
5
6
 
6
7
  type Mode = 'single' | 'multiple' | 'range'
7
8
  type DropdownRef = {
@@ -160,7 +161,7 @@ export function FieldDate({
160
161
  {
161
162
  prefix &&
162
163
  // Similar classNames to the input.tsx:IconWrapper()
163
- <span className="z-[0] col-start-1 row-start-1 self-center select-none justify-self-start text-input-base ml-3">
164
+ <span className="z-[0] col-start-1 row-start-1 self-center select-none justify-self-start text-input-base ml-[12px] ml-input-x">
164
165
  {prefix}
165
166
  </span>
166
167
  }
@@ -234,7 +235,7 @@ function TimePicker({ date, onChange }: TimePickerProps) {
234
235
  <button
235
236
  key={item}
236
237
  className={
237
- 'size-[33px] rounded-full flex justify-center items-center group-hover:bg-gray-100 '
238
+ `${dayButtonClassName} rounded-full flex justify-center items-center group-hover:bg-gray-100 `
238
239
  + (item === currentValue ? '!bg-input-border-focus text-white' : '')
239
240
  }
240
241
  onClick={() => handleTimeChange(type, item)}
@@ -1,10 +1,10 @@
1
1
  /* eslint-disable @typescript-eslint/no-explicit-any */
2
- // Maybe use fill-current tw class for lucide icons (https://github.com/lucide-icons/lucide/discussions/458)
2
+ // fill-current tw class for lucide icons (https://github.com/lucide-icons/lucide/discussions/458)
3
3
  import { css } from 'twin.macro'
4
4
  import { FieldCurrency, FieldCurrencyProps, FieldColor, FieldColorProps, FieldDate, FieldDateProps } from 'nitro-web'
5
5
  import { twMerge, getErrorFromState, deepFind } from 'nitro-web/util'
6
6
  import { Errors, type Error } from 'nitro-web/types'
7
- import { EnvelopeIcon, CalendarIcon, FunnelIcon, MagnifyingGlassIcon, EyeIcon, EyeSlashIcon } from '@heroicons/react/20/solid'
7
+ import { MailIcon, CalendarIcon, FunnelIcon, SearchIcon, EyeIcon, EyeOffIcon } from 'lucide-react'
8
8
  import { memo } from 'react'
9
9
 
10
10
  type FieldType = 'text' | 'password' | 'email' | 'filter' | 'search' | 'textarea' | 'currency' | 'date' | 'color'
@@ -27,7 +27,7 @@ type FieldExtraProps = {
27
27
  placeholder?: string
28
28
  }
29
29
  type IconWrapperProps = {
30
- iconPos: string
30
+ iconPos: 'left' | 'right'
31
31
  icon?: React.ReactNode
32
32
  [key: string]: unknown
33
33
  }
@@ -77,22 +77,22 @@ function FieldBase({ state, icon, iconPos: ip, ...props }: FieldProps) {
77
77
  if (type == 'password') {
78
78
  Icon = <IconWrapper
79
79
  iconPos={iconPos}
80
- icon={icon || inputType == 'password' ? <EyeSlashIcon /> : <EyeIcon />}
80
+ icon={icon || inputType == 'password' ? <EyeOffIcon /> : <EyeIcon />}
81
81
  onClick={() => setInputType(o => o == 'password' ? 'text' : 'password')}
82
- className="pointer-events-auto"
82
+ className="size-[15px] size-input-icon pointer-events-auto"
83
83
  />
84
84
  } else if (type == 'email') {
85
- Icon = <IconWrapper iconPos={iconPos} icon={icon || <EnvelopeIcon />} />
85
+ Icon = <IconWrapper iconPos={iconPos} icon={icon || <MailIcon />} className="size-[14px] size-input-icon" />
86
86
  } else if (type == 'filter') {
87
- Icon = <IconWrapper iconPos={iconPos} icon={icon || <FunnelIcon />} className="size-3" />
87
+ Icon = <IconWrapper iconPos={iconPos} icon={icon || <FunnelIcon />} className="size-[14px] size-input-icon" />
88
88
  } else if (type == 'search') {
89
- Icon = <IconWrapper iconPos={iconPos} icon={icon || <MagnifyingGlassIcon />} className="size-4" />
89
+ Icon = <IconWrapper iconPos={iconPos} icon={icon || <SearchIcon />} className="size-[14px] size-input-icon" />
90
90
  } else if (type == 'color') {
91
91
  Icon = <IconWrapper iconPos={iconPos} icon={icon || <ColorSvg hex={value}/>} className="size-[17px]" />
92
92
  } else if (type == 'date') {
93
- Icon = <IconWrapper iconPos={iconPos} icon={icon || <CalendarIcon />} className="size-4" />
94
- } else {
95
- Icon = <IconWrapper iconPos={iconPos} icon={icon} />
93
+ Icon = <IconWrapper iconPos={iconPos} icon={icon || <CalendarIcon />} className="size-[14px] size-input-icon" />
94
+ } else if (icon) {
95
+ Icon = <IconWrapper iconPos={iconPos} icon={icon} className="size-[14px] size-input-icon" />
96
96
  }
97
97
 
98
98
  // Classname
@@ -135,7 +135,7 @@ function FieldBase({ state, icon, iconPos: ip, ...props }: FieldProps) {
135
135
 
136
136
  function FieldContainer({ children, className, error }: { children: React.ReactNode, className?: string, error?: Error }) {
137
137
  return (
138
- <div css={style} className={twMerge(`mt-2.5 mb-6 mt-input-before mb-input-after grid grid-cols-1 nitro-field ${className || ''}`)}>
138
+ <div css={style} className={'mt-2.5 mb-6 ' + twMerge(`mt-input-before mb-input-after grid grid-cols-1 nitro-field ${className || ''}`)}>
139
139
  {children}
140
140
  {error && <div class="mt-1.5 text-xs text-danger-foreground nitro-error">{error.detail}</div>}
141
141
  </div>
@@ -143,15 +143,15 @@ function FieldContainer({ children, className, error }: { children: React.ReactN
143
143
  }
144
144
 
145
145
  function getInputClasses({ error, Icon, iconPos, type }: { error?: Error, Icon?: React.ReactNode, iconPos: string, type?: string }) {
146
- const pl = 'pl-[12px] pl-input-x'
147
- const pr = 'pr-[12px] pr-input-x'
146
+ // not twMerge
147
+ const px = 'px-[12px]'
148
148
  const py = 'py-[9px] py-input-y'
149
- const plWithIcon = type == 'color' ? 'pl-9' : 'pl-8' // was sm:pl-8 pl-8, etc
150
- const prWithIcon = type == 'color' ? 'pr-9' : 'pr-8'
151
149
  return (
152
- `block ${py} col-start-1 row-start-1 w-full rounded-md bg-white text-input-base outline outline-1 -outline-offset-1 ` +
153
- 'placeholder:text-input-placeholder focus:outline focus:outline-2 focus:-outline-offset-2 ' +
154
- (iconPos == 'right' && Icon ? `${pl} ${prWithIcon} ` : (Icon ? `${plWithIcon} ${pr} ` : `${pl} ${pr} `)) +
150
+ 'block col-start-1 row-start-1 w-full rounded-md bg-white text-input-base outline outline-1 -outline-offset-1 ' +
151
+ 'placeholder:text-input-placeholder focus:outline focus:outline-2 focus:-outline-offset-2 ' + `${py} ${px} ` +
152
+ (iconPos == 'right' && Icon ? 'pr-[32px] pr-input-x-icon pl-input-x ' : '') +
153
+ (iconPos == 'left' && Icon ? 'pl-[32px] pl-input-x-icon pr-input-x ' : 'px-input-x ') +
154
+ (iconPos == 'left' && Icon && type == 'color' ? 'indent-[5px] ' : '') +
155
155
  (error
156
156
  ? 'text-danger-foreground outline-danger focus:outline-danger '
157
157
  : 'text-input outline-input-border focus:outline-input-border-focus ') +
@@ -166,8 +166,8 @@ function IconWrapper({ icon, iconPos, ...props }: IconWrapperProps) {
166
166
  <div
167
167
  {...props}
168
168
  className={
169
- 'z-[0] size-[14px] col-start-1 row-start-1 self-center text-[#c6c8ce] select-none ' +
170
- (iconPos == 'right' ? 'justify-self-end mr-3 ' : 'justify-self-start ml-3 ') +
169
+ 'z-[0] col-start-1 row-start-1 self-center text-[#c6c8ce] text-input-icon select-none [&>svg]:size-full ' +
170
+ (iconPos == 'right' ? 'justify-self-end mr-[12px] mr-input-x ' : 'justify-self-start ml-[12px] ml-input-x ') +
171
171
  props.className || ''
172
172
  }
173
173
  >{icon}</div>
@@ -220,4 +220,8 @@ const style = css`
220
220
  -webkit-appearance: none;
221
221
  margin: 0;
222
222
  }
223
+ /* tw4 we can use calc to determine the padding-left with css variables...
224
+ .inputt {
225
+ padding-left: calc(var(--input-x) * 2);
226
+ } */
223
227
  `
@@ -5,7 +5,8 @@ import ReactSelect, {
5
5
  components, ControlProps, createFilter, OptionProps, SingleValueProps, ClearIndicatorProps,
6
6
  DropdownIndicatorProps, MultiValueRemoveProps,
7
7
  } from 'react-select'
8
- import { ChevronUpDownIcon, CheckCircleIcon, XMarkIcon } from '@heroicons/react/20/solid'
8
+ import { CheckCircleIcon } from '@heroicons/react/20/solid'
9
+ import { ChevronsUpDownIcon, XIcon } from 'lucide-react'
9
10
  import { isFieldCached } from 'nitro-web'
10
11
  import { getErrorFromState, deepFind, twMerge } from 'nitro-web/util'
11
12
  import { Errors } from 'nitro-web/types'
@@ -67,7 +68,7 @@ function SelectBase({ id, containerId, minMenuWidth, name, prefix='', onChange,
67
68
  if (typeof state == 'object' && typeof value == 'undefined') value = ''
68
69
 
69
70
  return (
70
- <div css={style} class={twMerge(`mt-2.5 mb-6 mt-input-before mb-input-after nitro-select ${props.className||''}`)}>
71
+ <div css={style} class={'mt-2.5 mb-6 ' + twMerge(`mt-input-before mb-input-after nitro-select ${props.className||''}`)}>
71
72
  <ReactSelect
72
73
  /**
73
74
  * react-select prop quick reference (https://react-select.com/props#api):
@@ -211,7 +212,7 @@ function Option(props: OptionProps) {
211
212
  <components.Option className={data.className} {...props}>
212
213
  { _nitro?.mode == 'country' && <Flag flag={data.flag} /> }
213
214
  <span class="flex-auto">{props.label}</span>
214
- {props.isSelected && <CheckCircleIcon className="size-[22px] text-primary -my-1 -mx-1" />}
215
+ {props.isSelected && <CheckCircleIcon className="size-[22px] text-primary -my-1 -mx-0.5" />}
215
216
  </components.Option>
216
217
  )
217
218
  }
@@ -219,7 +220,7 @@ function Option(props: OptionProps) {
219
220
  const DropdownIndicator = (props: DropdownIndicatorProps) => {
220
221
  return (
221
222
  <components.DropdownIndicator {...props}>
222
- <ChevronUpDownIcon className="text-gray-400 size-[17px] -my-0.5 -mx-0.5" />
223
+ <ChevronsUpDownIcon size={15} className="text-gray-400 -my-0.5 -mx-[1px]" />
223
224
  </components.DropdownIndicator>
224
225
  )
225
226
  }
@@ -227,7 +228,7 @@ const DropdownIndicator = (props: DropdownIndicatorProps) => {
227
228
  const ClearIndicator = (props: ClearIndicatorProps) => {
228
229
  return (
229
230
  <components.ClearIndicator {...props}>
230
- <XMarkIcon className="size-4" />
231
+ <XIcon size={14} />
231
232
  </components.ClearIndicator>
232
233
  )
233
234
  }
@@ -235,7 +236,7 @@ const ClearIndicator = (props: ClearIndicatorProps) => {
235
236
  const MultiValueRemove = (props: MultiValueRemoveProps) => {
236
237
  return (
237
238
  <components.MultiValueRemove {...props}>
238
- <XMarkIcon className="size-[1em] p-[1px]" />
239
+ <XIcon className="size-[1em] p-[1px]" />
239
240
  </components.MultiValueRemove>
240
241
  )
241
242
  }
@@ -258,7 +259,7 @@ const selectStyles = {
258
259
  focus: 'outline-2 -outline-offset-2 outline-input-border-focus',
259
260
  error: 'outline-danger',
260
261
  },
261
- valueContainer: 'py-[9px] px-[12px] py-input-y px-input-x gap-1',
262
+ valueContainer: 'py-[9px] px-[12px] py-input-y px-input-x gap-1', // dont twMerge (input-x is optional)
262
263
  // Input container objects
263
264
  input: {
264
265
  base: 'text-input',
@@ -187,10 +187,10 @@ export function Styleguide({ className, elements, children }: StyleguideProps) {
187
187
  <div><Button color="primary" size="sm">*-sm button</Button></div>
188
188
  <div><Button color="primary">*-md (default)</Button></div>
189
189
  <div><Button color="primary" size="lg">*-lg button</Button></div>
190
- <div><Button IconLeft={<Check size={19} className="-my-5 -mx-0.5" />}>IconLeft</Button></div>
191
- <div><Button IconLeft={<Check size={19} className="-my-5 -mx-0.5" />}
190
+ <div><Button IconLeft={<Check size={19} className="-my-5" />}>IconLeft</Button></div>
191
+ <div><Button IconLeft={<Check size={19} className="-my-5" />}
192
192
  className="w-[160px]">IconLeft 160px</Button></div>
193
- <div><Button IconLeftEnd={<Check size={19} className="-my-5 -mx-0.5" />}
193
+ <div><Button IconLeftEnd={<Check size={19} className="-my-5" />}
194
194
  className="w-[190px]">IconLeftEnd 190px</Button></div>
195
195
  <div><Button IconRight="v">IconRight</Button></div>
196
196
  <div><Button IconRightEnd="v" className="w-[190px]">IconRightEnd 190px</Button></div>
@@ -204,18 +204,21 @@ export function Styleguide({ className, elements, children }: StyleguideProps) {
204
204
  <div class="grid grid-cols-3 gap-x-6 mb-4">
205
205
  <div>
206
206
  <label for="input2">Label</label>
207
- <Checkbox name="input2" type="toggle" text="Toggle sm" subtext="some additional text here." class="!mb-0" defaultChecked />
208
- <Checkbox name="input3" type="toggle" text="Toggle md" size="md" subtext="some additional text here." />
207
+ <Checkbox name="input2" type="toggle" text="Toggle sm" subtext="some additional text here." class="!mb-0"
208
+ state={state} onChange={(e) => onChange(setState, e)} />
209
+ <Checkbox name="input3" type="toggle" text="Toggle 22px" subtext="some additional text here." size={22} />
209
210
  </div>
210
211
  <div>
211
212
  <label for="input1">Label</label>
212
- <Checkbox name="input1" type="radio" text="Radio 1" subtext="some additional text here 1." id="input1-1" class="!mb-0"
213
+ <Checkbox name="input1" type="radio" text="Radio" subtext="some additional text here 1." id="input1-1" class="!mb-0"
213
214
  defaultChecked />
214
- <Checkbox name="input1" type="radio" text="Radio 2" subtext="some additional text here 2." id="input1-2" class="!mt-0" />
215
+ <Checkbox name="input1" type="radio" text="Radio 16px" subtext="some additional text here 2." id="input1-2" size={16} />
215
216
  </div>
216
217
  <div>
217
218
  <label for="input0">Label</label>
218
- <Checkbox name="input0" type="checkbox" text="Checkbox" subtext="some additional text here." defaultChecked />
219
+ <Checkbox name="input0" type="checkbox" text="Checkbox" subtext="some additional text here." class="!mb-0" defaultChecked />
220
+ <Checkbox name="input0.1" type="checkbox" text="Checkbox 16px" size={16}
221
+ subtext="some additional text here which is a bit longer that will be line-wrap to the next line." />
219
222
  </div>
220
223
  </div>
221
224
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "nitro-web",
3
- "version": "0.0.72",
3
+ "version": "0.0.74",
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
@@ -721,18 +721,13 @@ export function toArray<T>(variable: T | undefined): (T extends any[] ? T : T[])
721
721
  * @returns {string}
722
722
  */
723
723
  export function trim(string: string): string;
724
- /**
725
- * Merge tailwind classes, but ignore classes that shouldn't be merged, and intended as an override
726
- * @param {...string} args
727
- * @returns {string}
728
- */
729
- export function twMerge(...args: string[]): string;
730
724
  /**
731
725
  * Capitalize the first letter of a string
732
726
  * @param {string} string
733
727
  * @returns {string}
734
728
  */
735
729
  export function ucFirst(string: string): string;
730
+ export const twMerge: (...classLists: import("tailwind-merge").ClassNameValue[]) => string;
736
731
  /**
737
732
  * Returns a list of response errors
738
733
  */
@@ -1 +1 @@
1
- {"version":3,"file":"util.d.ts","sourceRoot":"","sources":["../util.js"],"names":[],"mappings":"AAkBA;;GAEG;AACH;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EA+BC;AAED;;;;;;;;;GASG;AACH,yBARa,OAAO,OAAO,EAAE,WAAW,CAoBvC;AAED;;;;;GAKG;AACH,8BAJW,MAAM,cACN;IAAC,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAAA;CAAC,GACrB,MAAM,CAKlB;AAED;;;;;;GAMG;AACH,+BALW,MAAM,oBACN,OAAO,gBACP,OAAO,GACL,MAAM,CAelB;AAED;;;;;GAKG;AACH,sCAJW,MAAM,wBACN,OAAO,GACL,MAAM,CAMlB;AAED;;;;GAIG;AACH,sCAHW,MAAM,GACJ,MAAM,CAIlB;AAED;;;;GAIG;AACH,iCAHW,MAAM,GACJ,MAAM,CAIlB;AAED;;;;;;GAMG;AACH,gCALW,MAAM,aACN,MAAM,oBACN,MAAM,GACJ,MAAM,CAUlB;AAED;;;;GAIG;AACH,0CAHW,MAAM,GACJ,MAAM,CAMlB;AAED;;;;;;;;;;;GAWG;AACH,4BAVW,MAAM,GAAC,IAAI,WACX,MAAM,aACN,MAAM,GACJ,MAAM,CAsBlB;AAED;;;;;;;;;;;;;;;;;;GAkBG;AACH,yBAlBuC,CAAC,SAA3B,CAAE,GAAG,IAAI,EAAE,GAAG,EAAE,KAAK,GAAI,QAI3B,CAAC,SACD,MAAM,YACN;IACN,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB,GACS,CAAC,CAAC,GAAG,IAAI,EAAE,UAAU,CAAC,CAAC,CAAC,KAAK,UAAU,CAAC,CAAC,CAAC,CAAC,GAAG;IACpD,MAAM,EAAE,MAAM,IAAI,CAAC;IACnB,KAAK,EAAE,MAAM,UAAU,CAAC,CAAC,CAAC,CAAA;CAC7B,CAuKH;AAED;;;;;GAKG;AACH,yBAJa,CAAC,OACH,CAAC,GACC,CAAC,CAgBb;AAED;;;;;GAKG;AACH,8BAJW,MAAM,GAAC,GAAG,EAAE,QACZ,MAAM,GACJ,OAAO,CAgBnB;AAED;;;;;;;GAOG;AACH,yBANa,CAAC,OACH,CAAC,QACD,MAAM,SACN,OAAO,WAAS,GACd,CAAC,CA8Bb;AAED;;;;;;GAMG;AACH,0BALW;IAAC,CAAC,GAAG,EAAE,MAAM,GAAG,GAAG,CAAA;CAAC,GAAC,EAAE,GAAC,IAAI,gCAE5B,MAAM,GACJ,MAAM,GAAC,EAAE,GAAC,IAAI,CAmB1B;AAED;;;;;;;;;GASG;AACH,mCARW,MAAM,GAAC,IAAI,GAAC,IAAI,YAChB,MAAM,SACN,MAAM,QACN,MAAM,GACJ,IAAI,CA+BhB;AAED;;;;;GAKG;AACH,mCAJW,MAAM,iBACN,OAAO,GACL,MAAM,CAMlB;AAED;;;;GAIG;AACH,mCAHW,MAAM,GACJ,MAAM,CAWlB;AAED;;;;;;;;GAQG;AACH,8BAPW,MAAM,QACN;IAAE,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAAC,OAAO,CAAC,EAAE,OAAO,CAAC;IAAC,iBAAiB,CAAC,EAAE,OAAO,CAAC;IAAC,kBAAkB,CAAC,EAAE,OAAO,CAAA;CAAE,qBAC5G,QAAQ,cACR,MAAM,GACJ,QAAQ,CAwEpB;AAED;;;;GAIG;AACH,iCAHW;IAAC,SAAS,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAA;CAAC,GACnC,MAAM,CAIlB;AAED;;;;GAIG;AACH,sCAHW,MAAM,GACJ,MAAM,EAAE,CASpB;AAED;;;;GAIG;AACH,6CAHW;IAAE,CAAC,GAAG,EAAE,MAAM,GAAG;QAAE,IAAI,EAAE,MAAM,CAAA;KAAE,CAAA;CAAE,GACjC;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,EAAE,CAS5D;AAED;;;;GAIG;AACH,+CAHW;IAAE,CAAC,GAAG,EAAE,MAAM,GAAG;QAAE,IAAI,EAAE,MAAM,CAAA;KAAE,CAAA;CAAE,GACjC;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,EAAE,CAS9C;AAED;;;;;GAKG;AACH,yCAJW;IAAE,MAAM,CAAC,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,EAAE,CAAA;CAAE,GAAC,SAAS,QAC1D,MAAM,GACJ;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,GAAC,SAAS,CAQvD;AAED;;;;;GAKG;AACH,uCAJW,MAAM,iBACN,MAAM,GACJ,MAAM,CAYlB;AAED;;;;;GAKG;AACH,qCAJW;IAAE,IAAI,EAAE,CAAC,GAAG,IAAI,EAAE,MAAM,EAAE,KAAK,MAAM,CAAA;CAAE,QACvC,MAAM,GACJ,MAAM,CAYlB;AAED;;;;GAIG;AACH,6DAHW,MAAM,GACJ,OAAO,CAAC,OAAO,mBAAmB,EAAE,MAAM,GAAC,IAAI,CAAC,CAI5D;AAED;;;;;;;;;;;GAWG;AACH,wCAHW,aAAa,GACX,UAAU,EAAE,CAgCxB;AAED;;;;;;GAMG;AACH,+BALW,GAAG,EAAE,UACL,OAAO,QACP,MAAM,GACJ,OAAO,CAcnB;AAED;;;;GAIG;AACH,kCAHW,OAAO,GACL,OAAO,CAInB;AAED;;;;GAIG;AACH,iCAHW,OAAO,GACL,OAAO,CAInB;AAED;;;;GAIG;AACH,oCAHW,OAAO,GACL,OAAO,CAInB;AAED;;;;GAIG;AACH,+BAHW,MAAM,GACJ,OAAO,CAMnB;AAED;;;;;GAKG;AACH,8BAJW;IAAC,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAA;CAAC,GAAC,IAAI,qBAC7B,OAAO,GACL,OAAO,CASnB;AAED;;;;GAIG;AACH,qCAHW,OAAO,GACL,OAAO,CAInB;AAED;;;;GAIG;AACH,+BAHW,OAAO,GACL,OAAO,CAmBnB;AAED;;;;GAIG;AACH,mCAHW,OAAO,GACL,OAAO,CAInB;AAED;;;;GAIG;AACH,mCAHW,OAAO,GACL,OAAO,CAKnB;AAED;;;;GAIG;AACH,kCAHW,OAAO,GACL,OAAO,CAInB;AAED;;;;GAIG;AACH,mCAHW,OAAO,GACL,OAAO,CAInB;AAED;;;;GAIG;AACH,gCAHW,MAAM,GACJ,MAAM,CAIlB;AAED;;;;;;GAMG;AACH,kCALW,MAAM,QACN,MAAM,iBACN,OAAO,GACL,MAAM,CAalB;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AACH,qCAxBW,MAAM,mBACN,KAAK,GAAC,GAAG,aACT,KAAK,GACH,CAAC,KAAK,EAAE,KAAK,CAAC,GAAC,IAAI,CAuC/B;AAED;;;;;;;;;GASG;AACH,qDARW;IACN,IAAI,CAAC,EAAE;QAAC,UAAU,EAAE,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;QAAC,QAAQ,EAAE,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;KAAC,CAAA;IACjE,QAAQ,CAAC,EAAE;QAAC,WAAW,EAAE,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;KAAC,CAAA;CAC3C,MACO,MAAM,UACN,MAAM,OA+ChB;AAED;;;;;GAKG;AACH,6CAJW,MAAM,EAAE,UACR,MAAM,EAAE,GACP,MAAM,CAgBjB;AAED;;;;GAIG;AACH,kCAHW;IAAE,CAAC,GAAG,EAAE,MAAM,GAAG,GAAG,CAAA;CAAE,MACtB,CAAC,KAAK,EAAE,GAAG,EAAE,GAAG,EAAE,MAAM,KAAK,GAAG;;EAS1C;AAED;;;;;GAKG;AACH,0BAJW;IAAE,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAA;CAAE,UAC1B,MAAM,EAAE,GACN;IAAE,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAA;CAAE,CAStC;AAED;;;;;;;;;;;;;GAaG;AACH,yBAVa,CAAC,YACH,KAAK,CAAC,QAAQ,CAAC,KAAK,CAAC,cAAc,CAAC,CAAC,CAAC,CAAC,oBACvC;IAAC,MAAM,EAAE;QAAC,IAAI,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,OAAO,CAAA;KAAC,CAAA;CAAC,GAAC,CAAC,MAAM,EAAE,WAAS,OAAO,CAAC,8BAEjE,OAAO,CAAC,CAAC,CAAC,CA2DtB;AAED;;;;;;GAMG;AACH,0BALW,MAAM,YACN,MAAM,eACN,MAAM,GACJ,MAAM,CAUlB;AAED;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,oCAtBW;IAAE,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAAA;CAAE,UAOzB;IAAE,CAAC,GAAG,EAAE,MAAM,GAAG,QAAQ,GAAC,QAAQ,GAAC,QAAQ,GAAC,WAAW,GAAC,MAAM,EAAE,CAAA;CAAE;;cAgBzB,MAAM;eAAS,MAAM;;iBAAe,MAAM;;EAyC7F;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,wCAfW;IAAE,eAAe,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,SACzC;IAAE,IAAI,CAAC,EAAE,MAAM,CAAC;IAAC,IAAI,CAAC,EAAE,GAAG,GAAC,IAAI,CAAC;IAAC,MAAM,CAAC,EAAE,MAAM,CAAA;CAAE,UAMnD,MAAM;;;;;;EA4BhB;AAED;;;;GAIG;AACH,0BAHW;IAAE,CAAC,GAAG,EAAE,MAAM,GAAG,GAAG,CAAA;CAAE,QACtB,MAAM,GAAC,MAAM,GAAC,MAAM,EAAE,GAAC,MAAM,EAAE;;EAiBzC;AAED;;;;;;GAMG;AACH,0CAJW,MAAM,iBACN,OAAO,GACL;IAAC,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,GAAC,IAAI,CAAA;CAAC,CAqBxC;AAED;;;;GAIG;AACH,yCAHW,MAAM,GACJ,MAAM,EAAE,CAOpB;AAED;;;;GAIG;AACH,kCAHW;IAAC,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAA;CAAC,GACtB,MAAM,CAclB;AAED;;;;;;;;;;;GAWG;AACH,+BAVW,MAAM,SACN;IAAE,CAAC,GAAG,EAAE,MAAM,GAAG,GAAG,CAAA;CAAE,UACtB;IAAC,cAAc,CAAC,WAAU;CAAC,cAC3B,CAAC,OAAO,EAAE,CAAC,KAAK,EAAE,OAAO,KAAK,IAAI,CAAC,GACjC,OAAO,CAAC,GAAG,CAAC,CAyDxB;AAED;;;;GAIG;AACH,0CAHW,EAAE,GAAC;IAAC,CAAC,GAAG,EAAE,MAAM,GAAG,GAAG,CAAA;CAAC,GACrB,EAAE,GAAC;IAAC,CAAC,GAAG,EAAE,MAAM,GAAG,GAAG,CAAA;CAAC,CAcnC;AAED;;;;;;;;GAQG;AACH,gCANW,MAAM,gBACN,KAAK,EAAE,GAAC,KAAK,SACb,MAAM,MACN,MAAM,GACJ,MAAM,CAclB;AAED;;;;GAIG;AACH,qCAHW,MAAM,GACJ,MAAM,CAMlB;AAED;;;;;;;;GAQG;AACH,yCAPW,MAAM,gBACN,MAAM,wBAEN,MAAM,aADN,MAAM,GAEJ,MAAM,CA8ClB;AAED;;;;;GAKG;AACH,uCAJW,MAAM,cACN,OAAO,GACL,MAAM,CAelB;AAED;;;;;GAKG;AACH,gEAHW,MAAM,GACJ,OAAO,CAAC,IAAI,CAAC,CAMzB;AAED;;;;GAIG;AACH,oDAFW,aAAa,QAKvB;AAED;;;;;GAKG;AACH,sCAJW;IAAC,CAAC,GAAG,EAAE,MAAM,GAAG,GAAG,CAAA;CAAC,EAAE,OACtB,MAAM,GACJ,MAAM,EAAE,CAQpB;AAED;;;;;;;;;;;GAWG;AACH,+BAVW,CAAC,GAAG,IAAI,EAAE,GAAG,EAAE,KAAK,GAAG,SACvB,MAAM,YACN;IACL,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,QAAQ,CAAC,EAAE,OAAO,CAAC;CACrB,YAoBH;AAED;;;;;GAKG;AACH,wBAJa,CAAC,YACH,CAAC,GAAG,SAAS,GACX,CAAC,CAAC,SAAS,GAAG,EAAE,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,CASvC;AAED;;;;GAIG;AACH,6BAHW,MAAM,GACJ,MAAM,CAKlB;AAED;;;;GAIG;AACH,iCAHe,MAAM,EAAA,GACR,MAAM,CAqBlB;AAED;;;;GAIG;AACH,gCAHW,MAAM,GACJ,MAAM,CAKlB;;;;yBAj8BY;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE;;;;yBACjC;IAAE,MAAM,EAAE,MAAM;QAAE,OAAO,EAAE,MAAM,CAAA;KAAE,CAAA;CAAE;;;;8BACrC;IAAE,QAAQ,EAAE;QAAE,IAAI,EAAE;YAAE,MAAM,CAAC,EAAE,UAAU,EAAE,CAAC;YAAC,KAAK,CAAC,EAAE,MAAM,CAAC;YAAC,iBAAiB,CAAC,EAAE,MAAM,CAAA;SAAE,CAAA;KAAE,CAAA;CAAE;;;;4BAE7F,KAAK,GAAC,UAAU,EAAE,GAAC,UAAU,GAAC,eAAe,GAAC,MAAM,GAAC,GAAG;;;;oBAoNxD,CAAC,MAAM,EAAE,MAAM,CAAC;;;;kBAChB;IAAC,UAAU,EAAE,KAAK,CAAC;IAAC,QAAQ,EAAE,KAAK,CAAA;CAAC;;;;oBAigBpC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,MAAM,CAAC,EAAE,MAAM,CAAC;IAAC,IAAI,CAAC,EAAE,MAAM,CAAA;CAAC"}
1
+ {"version":3,"file":"util.d.ts","sourceRoot":"","sources":["../util.js"],"names":[],"mappings":"AAkBA;;GAEG;AACH;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EA+BC;AAED;;;;;;;;;GASG;AACH,yBARa,OAAO,OAAO,EAAE,WAAW,CAoBvC;AAED;;;;;GAKG;AACH,8BAJW,MAAM,cACN;IAAC,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAAA;CAAC,GACrB,MAAM,CAKlB;AAED;;;;;;GAMG;AACH,+BALW,MAAM,oBACN,OAAO,gBACP,OAAO,GACL,MAAM,CAelB;AAED;;;;;GAKG;AACH,sCAJW,MAAM,wBACN,OAAO,GACL,MAAM,CAMlB;AAED;;;;GAIG;AACH,sCAHW,MAAM,GACJ,MAAM,CAIlB;AAED;;;;GAIG;AACH,iCAHW,MAAM,GACJ,MAAM,CAIlB;AAED;;;;;;GAMG;AACH,gCALW,MAAM,aACN,MAAM,oBACN,MAAM,GACJ,MAAM,CAUlB;AAED;;;;GAIG;AACH,0CAHW,MAAM,GACJ,MAAM,CAMlB;AAED;;;;;;;;;;;GAWG;AACH,4BAVW,MAAM,GAAC,IAAI,WACX,MAAM,aACN,MAAM,GACJ,MAAM,CAsBlB;AAED;;;;;;;;;;;;;;;;;;GAkBG;AACH,yBAlBuC,CAAC,SAA3B,CAAE,GAAG,IAAI,EAAE,GAAG,EAAE,KAAK,GAAI,QAI3B,CAAC,SACD,MAAM,YACN;IACN,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB,GACS,CAAC,CAAC,GAAG,IAAI,EAAE,UAAU,CAAC,CAAC,CAAC,KAAK,UAAU,CAAC,CAAC,CAAC,CAAC,GAAG;IACpD,MAAM,EAAE,MAAM,IAAI,CAAC;IACnB,KAAK,EAAE,MAAM,UAAU,CAAC,CAAC,CAAC,CAAA;CAC7B,CAuKH;AAED;;;;;GAKG;AACH,yBAJa,CAAC,OACH,CAAC,GACC,CAAC,CAgBb;AAED;;;;;GAKG;AACH,8BAJW,MAAM,GAAC,GAAG,EAAE,QACZ,MAAM,GACJ,OAAO,CAgBnB;AAED;;;;;;;GAOG;AACH,yBANa,CAAC,OACH,CAAC,QACD,MAAM,SACN,OAAO,WAAS,GACd,CAAC,CA8Bb;AAED;;;;;;GAMG;AACH,0BALW;IAAC,CAAC,GAAG,EAAE,MAAM,GAAG,GAAG,CAAA;CAAC,GAAC,EAAE,GAAC,IAAI,gCAE5B,MAAM,GACJ,MAAM,GAAC,EAAE,GAAC,IAAI,CAmB1B;AAED;;;;;;;;;GASG;AACH,mCARW,MAAM,GAAC,IAAI,GAAC,IAAI,YAChB,MAAM,SACN,MAAM,QACN,MAAM,GACJ,IAAI,CA+BhB;AAED;;;;;GAKG;AACH,mCAJW,MAAM,iBACN,OAAO,GACL,MAAM,CAMlB;AAED;;;;GAIG;AACH,mCAHW,MAAM,GACJ,MAAM,CAWlB;AAED;;;;;;;;GAQG;AACH,8BAPW,MAAM,QACN;IAAE,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAAC,OAAO,CAAC,EAAE,OAAO,CAAC;IAAC,iBAAiB,CAAC,EAAE,OAAO,CAAC;IAAC,kBAAkB,CAAC,EAAE,OAAO,CAAA;CAAE,qBAC5G,QAAQ,cACR,MAAM,GACJ,QAAQ,CAwEpB;AAED;;;;GAIG;AACH,iCAHW;IAAC,SAAS,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAA;CAAC,GACnC,MAAM,CAIlB;AAED;;;;GAIG;AACH,sCAHW,MAAM,GACJ,MAAM,EAAE,CASpB;AAED;;;;GAIG;AACH,6CAHW;IAAE,CAAC,GAAG,EAAE,MAAM,GAAG;QAAE,IAAI,EAAE,MAAM,CAAA;KAAE,CAAA;CAAE,GACjC;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,EAAE,CAS5D;AAED;;;;GAIG;AACH,+CAHW;IAAE,CAAC,GAAG,EAAE,MAAM,GAAG;QAAE,IAAI,EAAE,MAAM,CAAA;KAAE,CAAA;CAAE,GACjC;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,EAAE,CAS9C;AAED;;;;;GAKG;AACH,yCAJW;IAAE,MAAM,CAAC,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,EAAE,CAAA;CAAE,GAAC,SAAS,QAC1D,MAAM,GACJ;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,GAAC,SAAS,CAQvD;AAED;;;;;GAKG;AACH,uCAJW,MAAM,iBACN,MAAM,GACJ,MAAM,CAYlB;AAED;;;;;GAKG;AACH,qCAJW;IAAE,IAAI,EAAE,CAAC,GAAG,IAAI,EAAE,MAAM,EAAE,KAAK,MAAM,CAAA;CAAE,QACvC,MAAM,GACJ,MAAM,CAYlB;AAED;;;;GAIG;AACH,6DAHW,MAAM,GACJ,OAAO,CAAC,OAAO,mBAAmB,EAAE,MAAM,GAAC,IAAI,CAAC,CAI5D;AAED;;;;;;;;;;;GAWG;AACH,wCAHW,aAAa,GACX,UAAU,EAAE,CAgCxB;AAED;;;;;;GAMG;AACH,+BALW,GAAG,EAAE,UACL,OAAO,QACP,MAAM,GACJ,OAAO,CAcnB;AAED;;;;GAIG;AACH,kCAHW,OAAO,GACL,OAAO,CAInB;AAED;;;;GAIG;AACH,iCAHW,OAAO,GACL,OAAO,CAInB;AAED;;;;GAIG;AACH,oCAHW,OAAO,GACL,OAAO,CAInB;AAED;;;;GAIG;AACH,+BAHW,MAAM,GACJ,OAAO,CAMnB;AAED;;;;;GAKG;AACH,8BAJW;IAAC,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAA;CAAC,GAAC,IAAI,qBAC7B,OAAO,GACL,OAAO,CASnB;AAED;;;;GAIG;AACH,qCAHW,OAAO,GACL,OAAO,CAInB;AAED;;;;GAIG;AACH,+BAHW,OAAO,GACL,OAAO,CAmBnB;AAED;;;;GAIG;AACH,mCAHW,OAAO,GACL,OAAO,CAInB;AAED;;;;GAIG;AACH,mCAHW,OAAO,GACL,OAAO,CAKnB;AAED;;;;GAIG;AACH,kCAHW,OAAO,GACL,OAAO,CAInB;AAED;;;;GAIG;AACH,mCAHW,OAAO,GACL,OAAO,CAInB;AAED;;;;GAIG;AACH,gCAHW,MAAM,GACJ,MAAM,CAIlB;AAED;;;;;;GAMG;AACH,kCALW,MAAM,QACN,MAAM,iBACN,OAAO,GACL,MAAM,CAalB;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AACH,qCAxBW,MAAM,mBACN,KAAK,GAAC,GAAG,aACT,KAAK,GACH,CAAC,KAAK,EAAE,KAAK,CAAC,GAAC,IAAI,CAuC/B;AAED;;;;;;;;;GASG;AACH,qDARW;IACN,IAAI,CAAC,EAAE;QAAC,UAAU,EAAE,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;QAAC,QAAQ,EAAE,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;KAAC,CAAA;IACjE,QAAQ,CAAC,EAAE;QAAC,WAAW,EAAE,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;KAAC,CAAA;CAC3C,MACO,MAAM,UACN,MAAM,OA+ChB;AAED;;;;;GAKG;AACH,6CAJW,MAAM,EAAE,UACR,MAAM,EAAE,GACP,MAAM,CAgBjB;AAED;;;;GAIG;AACH,kCAHW;IAAE,CAAC,GAAG,EAAE,MAAM,GAAG,GAAG,CAAA;CAAE,MACtB,CAAC,KAAK,EAAE,GAAG,EAAE,GAAG,EAAE,MAAM,KAAK,GAAG;;EAS1C;AAED;;;;;GAKG;AACH,0BAJW;IAAE,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAA;CAAE,UAC1B,MAAM,EAAE,GACN;IAAE,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAA;CAAE,CAStC;AAED;;;;;;;;;;;;;GAaG;AACH,yBAVa,CAAC,YACH,KAAK,CAAC,QAAQ,CAAC,KAAK,CAAC,cAAc,CAAC,CAAC,CAAC,CAAC,oBACvC;IAAC,MAAM,EAAE;QAAC,IAAI,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,OAAO,CAAA;KAAC,CAAA;CAAC,GAAC,CAAC,MAAM,EAAE,WAAS,OAAO,CAAC,8BAEjE,OAAO,CAAC,CAAC,CAAC,CA2DtB;AAED;;;;;;GAMG;AACH,0BALW,MAAM,YACN,MAAM,eACN,MAAM,GACJ,MAAM,CAUlB;AAED;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,oCAtBW;IAAE,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAAA;CAAE,UAOzB;IAAE,CAAC,GAAG,EAAE,MAAM,GAAG,QAAQ,GAAC,QAAQ,GAAC,QAAQ,GAAC,WAAW,GAAC,MAAM,EAAE,CAAA;CAAE;;cAgBzB,MAAM;eAAS,MAAM;;iBAAe,MAAM;;EAyC7F;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,wCAfW;IAAE,eAAe,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,SACzC;IAAE,IAAI,CAAC,EAAE,MAAM,CAAC;IAAC,IAAI,CAAC,EAAE,GAAG,GAAC,IAAI,CAAC;IAAC,MAAM,CAAC,EAAE,MAAM,CAAA;CAAE,UAMnD,MAAM;;;;;;EA4BhB;AAED;;;;GAIG;AACH,0BAHW;IAAE,CAAC,GAAG,EAAE,MAAM,GAAG,GAAG,CAAA;CAAE,QACtB,MAAM,GAAC,MAAM,GAAC,MAAM,EAAE,GAAC,MAAM,EAAE;;EAiBzC;AAED;;;;;;GAMG;AACH,0CAJW,MAAM,iBACN,OAAO,GACL;IAAC,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,GAAC,IAAI,CAAA;CAAC,CAqBxC;AAED;;;;GAIG;AACH,yCAHW,MAAM,GACJ,MAAM,EAAE,CAOpB;AAED;;;;GAIG;AACH,kCAHW;IAAC,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAA;CAAC,GACtB,MAAM,CAclB;AAED;;;;;;;;;;;GAWG;AACH,+BAVW,MAAM,SACN;IAAE,CAAC,GAAG,EAAE,MAAM,GAAG,GAAG,CAAA;CAAE,UACtB;IAAC,cAAc,CAAC,WAAU;CAAC,cAC3B,CAAC,OAAO,EAAE,CAAC,KAAK,EAAE,OAAO,KAAK,IAAI,CAAC,GACjC,OAAO,CAAC,GAAG,CAAC,CAyDxB;AAED;;;;GAIG;AACH,0CAHW,EAAE,GAAC;IAAC,CAAC,GAAG,EAAE,MAAM,GAAG,GAAG,CAAA;CAAC,GACrB,EAAE,GAAC;IAAC,CAAC,GAAG,EAAE,MAAM,GAAG,GAAG,CAAA;CAAC,CAcnC;AAED;;;;;;;;GAQG;AACH,gCANW,MAAM,gBACN,KAAK,EAAE,GAAC,KAAK,SACb,MAAM,MACN,MAAM,GACJ,MAAM,CAclB;AAED;;;;GAIG;AACH,qCAHW,MAAM,GACJ,MAAM,CAMlB;AAED;;;;;;;;GAQG;AACH,yCAPW,MAAM,gBACN,MAAM,wBAEN,MAAM,aADN,MAAM,GAEJ,MAAM,CA8ClB;AAED;;;;;GAKG;AACH,uCAJW,MAAM,cACN,OAAO,GACL,MAAM,CAelB;AAED;;;;;GAKG;AACH,gEAHW,MAAM,GACJ,OAAO,CAAC,IAAI,CAAC,CAMzB;AAED;;;;GAIG;AACH,oDAFW,aAAa,QAKvB;AAED;;;;;GAKG;AACH,sCAJW;IAAC,CAAC,GAAG,EAAE,MAAM,GAAG,GAAG,CAAA;CAAC,EAAE,OACtB,MAAM,GACJ,MAAM,EAAE,CAQpB;AAED;;;;;;;;;;;GAWG;AACH,+BAVW,CAAC,GAAG,IAAI,EAAE,GAAG,EAAE,KAAK,GAAG,SACvB,MAAM,YACN;IACL,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,QAAQ,CAAC,EAAE,OAAO,CAAC;CACrB,YAoBH;AAED;;;;;GAKG;AACH,wBAJa,CAAC,YACH,CAAC,GAAG,SAAS,GACX,CAAC,CAAC,SAAS,GAAG,EAAE,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,CASvC;AAED;;;;GAIG;AACH,6BAHW,MAAM,GACJ,MAAM,CAKlB;AAwED;;;;GAIG;AACH,gCAHW,MAAM,GACJ,MAAM,CAKlB;AA3ED,2FAiEE;;;;yBAn+BW;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE;;;;yBACjC;IAAE,MAAM,EAAE,MAAM;QAAE,OAAO,EAAE,MAAM,CAAA;KAAE,CAAA;CAAE;;;;8BACrC;IAAE,QAAQ,EAAE;QAAE,IAAI,EAAE;YAAE,MAAM,CAAC,EAAE,UAAU,EAAE,CAAC;YAAC,KAAK,CAAC,EAAE,MAAM,CAAC;YAAC,iBAAiB,CAAC,EAAE,MAAM,CAAA;SAAE,CAAA;KAAE,CAAA;CAAE;;;;4BAE7F,KAAK,GAAC,UAAU,EAAE,GAAC,UAAU,GAAC,eAAe,GAAC,MAAM,GAAC,GAAG;;;;oBAoNxD,CAAC,MAAM,EAAE,MAAM,CAAC;;;;kBAChB;IAAC,UAAU,EAAE,KAAK,CAAC;IAAC,QAAQ,EAAE,KAAK,CAAA;CAAC;;;;oBAigBpC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,MAAM,CAAC,EAAE,MAAM,CAAC;IAAC,IAAI,CAAC,EAAE,MAAM,CAAA;CAAC"}
package/util.js CHANGED
@@ -1675,31 +1675,75 @@ export function trim (string) {
1675
1675
  return string.trim().replace(/\n\s+\n/g, '\n\n')
1676
1676
  }
1677
1677
 
1678
- /**
1679
- * Merge tailwind classes, but ignore classes that shouldn't be merged, and intended as an override
1680
- * @param {...string} args
1681
- * @returns {string}
1682
- */
1683
- export function twMerge(...args) {
1684
- const ignoredClasses = /** @type {string[]} */([])
1685
- const ignoreClasses = [
1686
- 'text-button-xs',
1687
- 'text-button-sm',
1688
- 'text-button-md',
1689
- 'text-button-lg',
1690
- 'text-input-base',
1691
- ]
1692
- const classes = args.filter(Boolean).join(' ').split(' ')
1678
+ import { createTailwindMerge, getDefaultConfig } from 'tailwind-merge'
1693
1679
 
1694
- const filteredClasses = classes.filter(c => {
1695
- if (ignoreClasses.includes(c)) {
1696
- ignoredClasses.push(c)
1697
- return false
1680
+ // Create a custom twMerge instance
1681
+ export const twMerge = createTailwindMerge(() => {
1682
+ const config = getDefaultConfig()
1683
+
1684
+ /**
1685
+ * @param {string[]} baseNames - base names for x-axis (e.g. 'input-x')
1686
+ * @returns {object} extended classGroups with new spacing classes
1687
+ */
1688
+ function newSpacingSizes(baseNames) {
1689
+ const obj = {
1690
+ pl: [...(/** @type {any} */(config.classGroups.pl) ?? [])],
1691
+ pr: [...(/** @type {any} */(config.classGroups.pr) ?? [])],
1692
+ pt: [...(/** @type {any} */(config.classGroups.pt) ?? [])],
1693
+ pb: [...(/** @type {any} */(config.classGroups.pb) ?? [])],
1694
+ px: [...(/** @type {any} */(config.classGroups.px) ?? [])],
1695
+ py: [...(/** @type {any} */(config.classGroups.py) ?? [])],
1696
+ p: [...(/** @type {any} */(config.classGroups.p) ?? [])],
1697
+ ml: [...(/** @type {any} */(config.classGroups.ml) ?? [])],
1698
+ mr: [...(/** @type {any} */(config.classGroups.mr) ?? [])],
1699
+ mt: [...(/** @type {any} */(config.classGroups.mt) ?? [])],
1700
+ mb: [...(/** @type {any} */(config.classGroups.mb) ?? [])],
1701
+ mx: [...(/** @type {any} */(config.classGroups.mx) ?? [])],
1702
+ my: [...(/** @type {any} */(config.classGroups.my) ?? [])],
1703
+ m: [...(/** @type {any} */(config.classGroups.m) ?? [])],
1704
+ gap: [...(/** @type {any} */(config.classGroups.gap) ?? [])],
1698
1705
  }
1699
- return true
1700
- })
1701
- return _twMerge(...filteredClasses) + ' ' + ignoredClasses.join(' ')
1702
- }
1706
+
1707
+ // Add both axes classes
1708
+ for (const baseName of baseNames) {
1709
+ obj.pl.push(`pl-${baseName}`)
1710
+ obj.pr.push(`pr-${baseName}`)
1711
+ obj.pt.push(`pt-${baseName}`)
1712
+ obj.pb.push(`pb-${baseName}`)
1713
+ obj.px.push(`px-${baseName}`)
1714
+ obj.py.push(`py-${baseName}`)
1715
+ obj.p.push(`p-${baseName}`)
1716
+ obj.ml.push(`ml-${baseName}`)
1717
+ obj.mr.push(`mr-${baseName}`)
1718
+ obj.mt.push(`mt-${baseName}`)
1719
+ obj.mb.push(`mb-${baseName}`)
1720
+ obj.mx.push(`mx-${baseName}`)
1721
+ obj.my.push(`my-${baseName}`)
1722
+ obj.m.push(`m-${baseName}`)
1723
+ obj.gap.push(`gap-${baseName}`)
1724
+ }
1725
+ return obj
1726
+ }
1727
+ return {
1728
+ ...config,
1729
+ classGroups: {
1730
+ ...config.classGroups,
1731
+ ...newSpacingSizes(['input-x', 'input-x-icon', 'input-y', 'input-before', 'input-after', 'input-icon']),
1732
+ 'shadow': [...(config.classGroups.shadow || []), 'shadow-dropdown-ul'],
1733
+ 'font-size': [...(config.classGroups['font-size'] || []), 'text-button-base', 'text-input-base'],
1734
+ },
1735
+ }
1736
+ // console.dir(
1737
+ // newSpacingSizes(['input-x', 'input-y', 'input-before', 'input-after']),
1738
+ // { depth: null }
1739
+ // )
1740
+ // console.log(customTwMerge('mb-1 mb-2 mb-input-x')) // mb-input-x
1741
+ // console.log(customTwMerge('mb-1 mb-2 my-input-y')) // my-input-y
1742
+ // console.log(customTwMerge('mb-1 my-input-y mb-2')) // my-input-y mb-2
1743
+ // console.log(customTwMerge('mb-1 my-input-y mb-2 my-input-x')) // my-input-x
1744
+ // console.log(customTwMerge('mx-1 my-input-y mb-2 my-input-x')) // mx-1 my-input-x
1745
+ // console.log(customTwMerge('text-xs text-base text-input text-button-base'))
1746
+ })
1703
1747
 
1704
1748
  /**
1705
1749
  * Capitalize the first letter of a string