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 (
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
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.
|
|
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 🚀",
|