nitro-web 0.0.203 → 0.0.204

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -6,10 +6,10 @@ import { type FieldCurrencyProps, FieldCurrency } from './field-currency'
6
6
  import { type FieldDateProps, FieldDate } from './field-date'
7
7
  import { twMerge, getErrorFromState, deepFind } from 'nitro-web/util'
8
8
  import { Errors, type Error } from 'nitro-web/types'
9
- import { MailIcon, CalendarIcon, FunnelIcon, SearchIcon, EyeIcon, EyeOffIcon, ClockIcon } from 'lucide-react'
10
- import { memo } from 'react'
9
+ import { MailIcon, CalendarIcon, FunnelIcon, SearchIcon, EyeIcon, EyeOffIcon, ClockIcon, PaperclipIcon } from 'lucide-react'
10
+ import { memo, useState } from 'react'
11
11
 
12
- type FieldType = 'text' | 'number' | 'password' | 'email' | 'filter' | 'search' | 'textarea' | 'currency' | 'date' | 'color'
12
+ type FieldType = 'text' | 'number' | 'password' | 'email' | 'filter' | 'search' | 'textarea' | 'currency' | 'date' | 'color' | 'file'
13
13
  type InputProps = React.InputHTMLAttributes<HTMLInputElement>
14
14
  type TextareaProps = React.TextareaHTMLAttributes<HTMLTextAreaElement>
15
15
  type FieldExtraProps = {
@@ -44,6 +44,7 @@ export type FieldProps = (
44
44
  | ({ type: 'currency' } & FieldCurrencyProps & FieldExtraProps)
45
45
  | ({ type: 'color' } & FieldColorProps & FieldExtraProps)
46
46
  | ({ type: 'date' } & FieldDateProps & FieldExtraProps)
47
+ | ({ type: 'file' } & InputProps & FieldExtraProps)
47
48
  )
48
49
  type IsFieldCachedProps = {
49
50
  name: string
@@ -74,11 +75,13 @@ function FieldBase({ state, icon, iconPos: ip, errorTitle, inputClassName, ...pr
74
75
  return type == 'password' ? 'password' : (type == 'textarea' ? 'textarea' : (type == 'number' ? 'number' : 'text'))
75
76
  })
76
77
 
77
- // Value: Input is always controlled if state is passed in
78
- if (typeof props.value !== 'undefined') value = props.value
79
- else if (typeof state == 'object') {
80
- const v = deepFind(state, props.name) ?? ''
81
- value = v
78
+ // Value: Input is always controlled if state is passed in (file inputs stay uncontrolled)
79
+ if (type !== 'file') {
80
+ if (typeof props.value !== 'undefined') value = props.value
81
+ else if (typeof state == 'object') {
82
+ const v = deepFind(state, props.name) ?? ''
83
+ value = v
84
+ }
82
85
  }
83
86
 
84
87
  // Icon
@@ -101,6 +104,8 @@ function FieldBase({ state, icon, iconPos: ip, errorTitle, inputClassName, ...pr
101
104
  Icon = <IconWrapper iconPos={iconPos} icon={icon || <ClockIcon />} className="size-[14px] size-input-icon" />
102
105
  } else if (type == 'date') {
103
106
  Icon = <IconWrapper iconPos={iconPos} icon={icon || <CalendarIcon />} className="size-[14px] size-input-icon" />
107
+ } else if (type == 'file') {
108
+ Icon = <IconWrapper iconPos={iconPos} icon={icon || <PaperclipIcon />} className="size-[14px] size-input-icon" />
104
109
  } else if (icon) {
105
110
  Icon = <IconWrapper iconPos={iconPos} icon={icon} className="size-[14px] size-input-icon" />
106
111
  }
@@ -141,6 +146,13 @@ function FieldBase({ state, icon, iconPos: ip, errorTitle, inputClassName, ...pr
141
146
  <FieldDate {...props} {...commonProps} Icon={Icon} />
142
147
  </FieldContainer>
143
148
  )
149
+ } else if (type == 'file') {
150
+ // const { className, ...rest } = props as Extract<FieldProps, { type: 'file' }>
151
+ return (
152
+ <FieldContainer error={error} className={props.className}>
153
+ {Icon}<input {...props} {...commonProps} type="file" />
154
+ </FieldContainer>
155
+ )
144
156
  }
145
157
  }
146
158
 
@@ -162,7 +174,7 @@ function getInputClasses({ error, Icon, iconPos, type }: { error?: Error, Icon?:
162
174
  const px = 'px-[12px]'
163
175
  const py = 'py-[9px] py-input-y'
164
176
  return (
165
- 'block col-start-1 row-start-1 w-full rounded-md bg-white disabled:bg-input-disabled-bg text-input-base outline outline-1 -outline-offset-1 ' +
177
+ 'block col-start-1 row-start-1 w-full rounded-md bg-white disabled:cursor-not-allowed disabled:bg-input-disabled-bg text-input-base outline outline-1 -outline-offset-1 ' +
166
178
  'placeholder:text-input-placeholder focus:outline focus:outline-2 focus:-outline-offset-2 (' +
167
179
  `${py} ${px} ` +
168
180
  (iconPos == 'right' && Icon ? 'pr-[32px] pr-input-x-icon pl-input-x ' : '') +
@@ -173,6 +185,12 @@ function getInputClasses({ error, Icon, iconPos, type }: { error?: Error, Icon?:
173
185
  ? 'text-danger-foreground outline-danger focus:outline-danger '
174
186
  : 'text-input outline-input-border focus:outline-input-border-focus disabled:text-input-disabled ') +
175
187
  (iconPos == 'right' ? 'justify-self-start ' : 'justify-self-end ') +
188
+ (type == 'file'
189
+ ? 'file:inline-flex file:shrink-0 file:cursor-pointer file:items-center file:justify-center ' +
190
+ 'file:rounded file:border-0 file:bg-transparent file:py-[0.1em] file:my-[-0.1em] file:px-[0.4em] file:ml-[-0.4em] file:mr-[0.7em] file:text-input-base file:font-medium file:text-input ' +
191
+ 'file:outline-none file:bg-gray-100 hover:file:bg-gray-200 '
192
+ : ''
193
+ ) +
176
194
  'nitro-input'
177
195
  )
178
196
  }
@@ -228,7 +246,7 @@ export function isFieldCached(prev: IsFieldCachedProps, next: IsFieldCachedProps
228
246
  }
229
247
 
230
248
  const style = css`
231
- input {
249
+ input:not([type='file']) {
232
250
  appearance: textfield;
233
251
  -moz-appearance: textfield;
234
252
  }
@@ -591,6 +591,10 @@ export function Styleguide({ className, elements, children, currencies, groups }
591
591
  <label for="firstName">First Name (disabled)</label>
592
592
  <Field name="firstName" state={state} onChange={(e) => onChange(e, setState)} disabled />
593
593
  </div>
594
+ <div>
595
+ <label for="file">File Input</label>
596
+ <Field name="file" type="file" state={state} onChange={(e) => onChange(e, setState)} />
597
+ </div>
594
598
  </div>
595
599
  </div>
596
600
  )}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "nitro-web",
3
- "version": "0.0.203",
3
+ "version": "0.0.204",
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 🚀",