@maestro-js/components 1.0.0-alpha.23 → 1.0.0-alpha.4
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/dist/components.json +1 -1
- package/package.json +3 -3
- package/src/components/alert-dialog.tsx +1 -4
- package/src/components/avatar.tsx +1 -1
- package/src/components/date-range.tsx +26 -3
- package/src/components/disclosure.tsx +5 -1
- package/src/components/helpers/form-field.tsx +27 -25
- package/src/components/link-tabs.tsx +14 -9
- package/src/components/multi-file-input.tsx +1 -3
- package/src/components/numeric-tag-field.tsx +1 -7
- package/src/components/table/table-container.type-test.ts +1 -4
- package/src/components/table/use-client-table.type-test.ts +12 -3
- package/src/components/table/use-server-table.type-test.ts +14 -13
- package/src/components/tabs.tsx +7 -8
- package/src/components/tag-field.tsx +1 -7
- package/src/components/text-field.tsx +1 -4
- package/src/utils/use-query-state.ts +1 -4
- package/src/utils/use-tab-indicator.ts +1 -2
package/package.json
CHANGED
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
"@types/react-dom": "^19.1.6",
|
|
9
9
|
"react-pdf-hook": "^1.0.4",
|
|
10
10
|
"vaul": "^1.1.2",
|
|
11
|
-
"@maestro-js/form": "1.0.0-alpha.
|
|
11
|
+
"@maestro-js/form": "1.0.0-alpha.4"
|
|
12
12
|
},
|
|
13
13
|
"peerDependencies": {
|
|
14
14
|
"@bundled-es-modules/pdfjs-dist": "3.6.172-alpha.1",
|
|
@@ -26,9 +26,9 @@
|
|
|
26
26
|
"react-router": ">=7",
|
|
27
27
|
"vite-env-only": "^3.0.2",
|
|
28
28
|
"vaul": ">=1",
|
|
29
|
-
"@maestro-js/form": "1.0.0-alpha.
|
|
29
|
+
"@maestro-js/form": "1.0.0-alpha.4"
|
|
30
30
|
},
|
|
31
|
-
"version": "1.0.0-alpha.
|
|
31
|
+
"version": "1.0.0-alpha.4",
|
|
32
32
|
"license": "UNLICENSED",
|
|
33
33
|
"engines": {
|
|
34
34
|
"node": ">=22.18.0"
|
|
@@ -100,10 +100,7 @@ function AlertDialog_({
|
|
|
100
100
|
'data-[exiting]:scale-95 data-[exiting]:opacity-0 data-[exiting]:translate-y-2'
|
|
101
101
|
)}
|
|
102
102
|
>
|
|
103
|
-
<Dialog
|
|
104
|
-
className={tw('outline-none bg-white rounded-xl shadow-xl ring-1 ring-black/5 w-full', className)}
|
|
105
|
-
role="alertdialog"
|
|
106
|
-
>
|
|
103
|
+
<Dialog className={tw('outline-none bg-white rounded-xl shadow-xl ring-1 ring-black/5 w-full', className)} role="alertdialog">
|
|
107
104
|
{({ close }) => (
|
|
108
105
|
<AlertDialogContext.Provider value={{ close }}>
|
|
109
106
|
<ButtonGroupContext.Provider
|
|
@@ -48,7 +48,7 @@ function stringAvatar(name: string) {
|
|
|
48
48
|
|
|
49
49
|
if (!first) return ''
|
|
50
50
|
|
|
51
|
-
const initials = names.length === 1 ?
|
|
51
|
+
const initials = names.length === 1 ? first[0] ?? '' : `${first[0] ?? ''}${last?.[0] ?? ''}`
|
|
52
52
|
|
|
53
53
|
return initials.toUpperCase()
|
|
54
54
|
}
|
|
@@ -13,7 +13,6 @@ import {
|
|
|
13
13
|
import { twMerge } from 'tailwind-merge'
|
|
14
14
|
import { parseDate, type CalendarDate, type DateValue } from '@internationalized/date'
|
|
15
15
|
import type { Iso } from 'iso-fns'
|
|
16
|
-
import { Icon } from './icon'
|
|
17
16
|
|
|
18
17
|
export type DateRangeRootAdditionalProps = {
|
|
19
18
|
defaultStart: Iso.Date | null
|
|
@@ -75,11 +74,11 @@ export function DateRangePicker(props: DateRangePickerProps) {
|
|
|
75
74
|
>
|
|
76
75
|
<header className="flex items-center justify-between mb-2 px-1">
|
|
77
76
|
<Button slot="previous" className="p-1 hover:bg-neutral-100 rounded cursor-pointer">
|
|
78
|
-
<
|
|
77
|
+
<ChevronLeft />
|
|
79
78
|
</Button>
|
|
80
79
|
<Heading className="text-sm font-semibold text-neutral-900 flex-1 text-center" />
|
|
81
80
|
<Button slot="next" className="p-1 hover:bg-neutral-100 rounded cursor-pointer">
|
|
82
|
-
<
|
|
81
|
+
<ChevronRight />
|
|
83
82
|
</Button>
|
|
84
83
|
</header>
|
|
85
84
|
<div className="flex gap-4">
|
|
@@ -136,3 +135,27 @@ export function DateRangePicker(props: DateRangePickerProps) {
|
|
|
136
135
|
</I18nProvider>
|
|
137
136
|
)
|
|
138
137
|
}
|
|
138
|
+
|
|
139
|
+
function ChevronLeft() {
|
|
140
|
+
return (
|
|
141
|
+
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" fill="currentColor" className="w-4 h-4">
|
|
142
|
+
<path
|
|
143
|
+
fillRule="evenodd"
|
|
144
|
+
d="M11.78 5.22a.75.75 0 0 1 0 1.06L8.06 10l3.72 3.72a.75.75 0 1 1-1.06 1.06l-4.25-4.25a.75.75 0 0 1 0-1.06l4.25-4.25a.75.75 0 0 1 1.06 0Z"
|
|
145
|
+
clipRule="evenodd"
|
|
146
|
+
/>
|
|
147
|
+
</svg>
|
|
148
|
+
)
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
function ChevronRight() {
|
|
152
|
+
return (
|
|
153
|
+
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" fill="currentColor" className="w-4 h-4">
|
|
154
|
+
<path
|
|
155
|
+
fillRule="evenodd"
|
|
156
|
+
d="M8.22 5.22a.75.75 0 0 1 1.06 0l4.25 4.25a.75.75 0 0 1 0 1.06l-4.25 4.25a.75.75 0 1 1-1.06-1.06L11.94 10 8.22 6.28a.75.75 0 0 1 0-1.06Z"
|
|
157
|
+
clipRule="evenodd"
|
|
158
|
+
/>
|
|
159
|
+
</svg>
|
|
160
|
+
)
|
|
161
|
+
}
|
|
@@ -92,7 +92,11 @@ function DisclosureHeader({
|
|
|
92
92
|
/>
|
|
93
93
|
<span
|
|
94
94
|
className={tw(
|
|
95
|
-
size === 'lg'
|
|
95
|
+
size === 'lg'
|
|
96
|
+
? 'text-lg font-semibold'
|
|
97
|
+
: size === 'md'
|
|
98
|
+
? 'text-base font-medium'
|
|
99
|
+
: 'text-sm font-medium',
|
|
96
100
|
isDisabled ? 'text-neutral-400' : 'text-neutral-700'
|
|
97
101
|
)}
|
|
98
102
|
>
|
|
@@ -76,32 +76,34 @@ type FieldGroupProps = {
|
|
|
76
76
|
onClick?: React.MouseEventHandler<HTMLDivElement>
|
|
77
77
|
}
|
|
78
78
|
|
|
79
|
-
const FieldGroup = React.forwardRef<HTMLDivElement, FieldGroupProps>(
|
|
80
|
-
|
|
81
|
-
|
|
79
|
+
const FieldGroup = React.forwardRef<HTMLDivElement, FieldGroupProps>(
|
|
80
|
+
({ children, className, onClick, ...opts }, ref) => {
|
|
81
|
+
const disabled = opts.isDisabled || opts.isReadonly
|
|
82
|
+
const shape = opts.shape === 'oval' ? 'rounded-full' : 'rounded'
|
|
82
83
|
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
}
|
|
84
|
+
return (
|
|
85
|
+
<Group
|
|
86
|
+
ref={ref}
|
|
87
|
+
className={tw(
|
|
88
|
+
'relative overflow-hidden ring-1 shadow-sm transition-all duration-200 max-w-96',
|
|
89
|
+
'focus-within:outline-2 focus-within:-outline-offset-1',
|
|
90
|
+
shape,
|
|
91
|
+
disabled && 'ring-neutral-200 bg-neutral-50 text-neutral-400 shadow-none cursor-not-allowed',
|
|
92
|
+
opts.isInvalid && 'ring-negative-300 bg-negative-50 focus-within:outline-negative-500',
|
|
93
|
+
opts.hasWarning && 'ring-notice-300 bg-notice-50 focus-within:outline-notice-500',
|
|
94
|
+
!opts.isInvalid &&
|
|
95
|
+
!opts.hasWarning &&
|
|
96
|
+
!disabled &&
|
|
97
|
+
'ring-black/10 hover:ring-black/20 focus-within:outline-primary-500',
|
|
98
|
+
className
|
|
99
|
+
)}
|
|
100
|
+
onClick={onClick}
|
|
101
|
+
>
|
|
102
|
+
{children}
|
|
103
|
+
</Group>
|
|
104
|
+
)
|
|
105
|
+
}
|
|
106
|
+
)
|
|
105
107
|
|
|
106
108
|
const FieldInput = React.forwardRef<HTMLInputElement, InputProps>((props, ref) => {
|
|
107
109
|
return (
|
|
@@ -36,10 +36,7 @@ export type LinkTabProps = {
|
|
|
36
36
|
|
|
37
37
|
// --- LinkTabList ---
|
|
38
38
|
|
|
39
|
-
const LinkTabListContext = React.createContext<{ color: TabColor; variant: TabVariant }>({
|
|
40
|
-
color: 'primary',
|
|
41
|
-
variant: 'underline'
|
|
42
|
-
})
|
|
39
|
+
const LinkTabListContext = React.createContext<{ color: TabColor; variant: TabVariant }>({ color: 'primary', variant: 'underline' })
|
|
43
40
|
|
|
44
41
|
function LinkTabList({ children, className, color = 'primary', variant = 'underline' }: LinkTabListProps) {
|
|
45
42
|
const containerRef = React.useRef<HTMLDivElement>(null)
|
|
@@ -51,7 +48,11 @@ function LinkTabList({ children, className, color = 'primary', variant = 'underl
|
|
|
51
48
|
<div role="tablist" className={tw(tabListInnerClasses[variant], className)}>
|
|
52
49
|
{children}
|
|
53
50
|
</div>
|
|
54
|
-
<div
|
|
51
|
+
<div
|
|
52
|
+
ref={indicatorRef}
|
|
53
|
+
className={getIndicatorClasses(variant, color)}
|
|
54
|
+
style={{ opacity: 0 }}
|
|
55
|
+
/>
|
|
55
56
|
</div>
|
|
56
57
|
</LinkTabListContext.Provider>
|
|
57
58
|
)
|
|
@@ -72,7 +73,13 @@ function LinkTab({ to, children, className, disabled, replace, end }: LinkTabPro
|
|
|
72
73
|
<span
|
|
73
74
|
role="tab"
|
|
74
75
|
aria-disabled="true"
|
|
75
|
-
className={tw(
|
|
76
|
+
className={tw(
|
|
77
|
+
baseClasses,
|
|
78
|
+
'outline-none',
|
|
79
|
+
TAB_INACTIVE_CLASSES,
|
|
80
|
+
TAB_DISABLED_CLASSES,
|
|
81
|
+
className
|
|
82
|
+
)}
|
|
76
83
|
>
|
|
77
84
|
{children}
|
|
78
85
|
</span>
|
|
@@ -90,9 +97,7 @@ function LinkTab({ to, children, className, disabled, replace, end }: LinkTabPro
|
|
|
90
97
|
baseClasses,
|
|
91
98
|
focusClasses,
|
|
92
99
|
isActive
|
|
93
|
-
? variant === 'oval'
|
|
94
|
-
? TAB_OVAL_SELECTED_CLASSES
|
|
95
|
-
: `${colors.text} font-bold`
|
|
100
|
+
? (variant === 'oval' ? TAB_OVAL_SELECTED_CLASSES : `${colors.text} font-bold`)
|
|
96
101
|
: `${TAB_INACTIVE_CLASSES} hover:text-neutral-700`,
|
|
97
102
|
className
|
|
98
103
|
)
|
|
@@ -162,9 +162,7 @@ export function MultiFileInput(props: MultiFileInputProps) {
|
|
|
162
162
|
<Icon name="document" className="h-5 w-5 text-neutral-400" />
|
|
163
163
|
<div className="min-w-0">
|
|
164
164
|
<p className="text-sm font-medium text-neutral-900 truncate">{fileName || 'File'}</p>
|
|
165
|
-
{fileItem.file && (
|
|
166
|
-
<p className="text-xs text-neutral-500">{formatFileSize(fileItem.file.size)}</p>
|
|
167
|
-
)}
|
|
165
|
+
{fileItem.file && <p className="text-xs text-neutral-500">{formatFileSize(fileItem.file.size)}</p>}
|
|
168
166
|
</div>
|
|
169
167
|
</div>
|
|
170
168
|
{!props.isDisabled && !props.isReadonly && (
|
|
@@ -180,13 +180,7 @@ export function NumericTagField(props: NumericTagFieldProps) {
|
|
|
180
180
|
|
|
181
181
|
<FormFieldComponents.LabelRow label={props.label} cornerHint={props.cornerHint} htmlFor={inputId} />
|
|
182
182
|
|
|
183
|
-
<FormFieldComponents.FieldGroup
|
|
184
|
-
isDisabled={props.isDisabled}
|
|
185
|
-
isInvalid={isInvalid}
|
|
186
|
-
hasWarning={hasWarning}
|
|
187
|
-
shape={props.shape}
|
|
188
|
-
onClick={() => inputRef.current?.focus()}
|
|
189
|
-
>
|
|
183
|
+
<FormFieldComponents.FieldGroup isDisabled={props.isDisabled} isInvalid={isInvalid} hasWarning={hasWarning} shape={props.shape} onClick={() => inputRef.current?.focus()}>
|
|
190
184
|
<div className="flex flex-wrap items-center gap-1.5 px-3 py-1.5 min-h-[38px] w-full">
|
|
191
185
|
{/* Display existing tags */}
|
|
192
186
|
{tags.map((tag, index) => (
|
|
@@ -28,10 +28,7 @@ type MyLocalization = TableLocalization<FC, SC>
|
|
|
28
28
|
// String union → DefaultTableFilter (has options array with typed values, no `type` discriminant)
|
|
29
29
|
const _selectFilter: TableFilterLocalization<StatusValue> = {
|
|
30
30
|
label: 'Status',
|
|
31
|
-
options: [
|
|
32
|
-
{ label: 'Active', value: 'active' },
|
|
33
|
-
{ label: 'Inactive', value: 'inactive' }
|
|
34
|
-
]
|
|
31
|
+
options: [{ label: 'Active', value: 'active' }, { label: 'Inactive', value: 'inactive' }]
|
|
35
32
|
}
|
|
36
33
|
|
|
37
34
|
// Date range → DateRangeTableFilter (type: 'date-range', no value-typed options)
|
|
@@ -67,7 +67,10 @@ function testLocalizationWithSelectFilter() {
|
|
|
67
67
|
}
|
|
68
68
|
})
|
|
69
69
|
|
|
70
|
-
type Loc = TableLocalization<
|
|
70
|
+
type Loc = TableLocalization<
|
|
71
|
+
ReturnType<typeof table.getFilterConfig>,
|
|
72
|
+
ReturnType<typeof table.getSortConfig>
|
|
73
|
+
>
|
|
71
74
|
|
|
72
75
|
type _LocFilterKeys = Expect<Equal<keyof Loc['filters'], 'status'>>
|
|
73
76
|
type _LocSortKeys = Expect<Equal<keyof Loc['sorts'], 'newest' | 'oldest'>>
|
|
@@ -108,7 +111,10 @@ function testLocalizationWithDateRangeFilter() {
|
|
|
108
111
|
}
|
|
109
112
|
})
|
|
110
113
|
|
|
111
|
-
type Loc = TableLocalization<
|
|
114
|
+
type Loc = TableLocalization<
|
|
115
|
+
ReturnType<typeof table.getFilterConfig>,
|
|
116
|
+
ReturnType<typeof table.getSortConfig>
|
|
117
|
+
>
|
|
112
118
|
|
|
113
119
|
// Valid: date-range filter accepts DateRangeTableFilter form
|
|
114
120
|
const _loc: Loc = {
|
|
@@ -201,7 +207,10 @@ function testNoFiltersOrSorts() {
|
|
|
201
207
|
getRowId: (row) => row.id
|
|
202
208
|
})
|
|
203
209
|
|
|
204
|
-
type Loc = TableLocalization<
|
|
210
|
+
type Loc = TableLocalization<
|
|
211
|
+
ReturnType<typeof table.getFilterConfig>,
|
|
212
|
+
ReturnType<typeof table.getSortConfig>
|
|
213
|
+
>
|
|
205
214
|
|
|
206
215
|
type _EmptyFilters = Expect<Equal<Loc['filters'], {}>>
|
|
207
216
|
type _EmptySorts = Expect<Equal<Loc['sorts'], {}>>
|
|
@@ -26,11 +26,7 @@ type Row = {
|
|
|
26
26
|
// =============================================================================
|
|
27
27
|
|
|
28
28
|
function testFilterAndSortInference() {
|
|
29
|
-
const serverTable = null as unknown as ServerTable.ServerTable<
|
|
30
|
-
Row,
|
|
31
|
-
{ status: 'active' | 'inactive' },
|
|
32
|
-
{ newest: true; oldest: true }
|
|
33
|
-
>
|
|
29
|
+
const serverTable = null as unknown as ServerTable.ServerTable<Row, { status: 'active' | 'inactive' }, { newest: true; oldest: true }>
|
|
34
30
|
|
|
35
31
|
const table = useServerTable(serverTable, { getRowId: (row) => row.id })
|
|
36
32
|
|
|
@@ -52,15 +48,14 @@ function testFilterAndSortInference() {
|
|
|
52
48
|
// =============================================================================
|
|
53
49
|
|
|
54
50
|
function testLocalizationWithSelectFilter() {
|
|
55
|
-
const serverTable = null as unknown as ServerTable.ServerTable<
|
|
56
|
-
Row,
|
|
57
|
-
{ status: 'active' | 'inactive' },
|
|
58
|
-
{ newest: true; oldest: true }
|
|
59
|
-
>
|
|
51
|
+
const serverTable = null as unknown as ServerTable.ServerTable<Row, { status: 'active' | 'inactive' }, { newest: true; oldest: true }>
|
|
60
52
|
|
|
61
53
|
const table = useServerTable(serverTable, { getRowId: (row) => row.id })
|
|
62
54
|
|
|
63
|
-
type Loc = TableLocalization<
|
|
55
|
+
type Loc = TableLocalization<
|
|
56
|
+
ReturnType<typeof table.getFilterConfig>,
|
|
57
|
+
ReturnType<typeof table.getSortConfig>
|
|
58
|
+
>
|
|
64
59
|
|
|
65
60
|
type _LocFilterKeys = Expect<Equal<keyof Loc['filters'], 'status'>>
|
|
66
61
|
type _LocSortKeys = Expect<Equal<keyof Loc['sorts'], 'newest' | 'oldest'>>
|
|
@@ -101,7 +96,10 @@ function testLocalizationWithDateRangeFilter() {
|
|
|
101
96
|
|
|
102
97
|
const table = useServerTable(serverTable, { getRowId: (row) => row.id })
|
|
103
98
|
|
|
104
|
-
type Loc = TableLocalization<
|
|
99
|
+
type Loc = TableLocalization<
|
|
100
|
+
ReturnType<typeof table.getFilterConfig>,
|
|
101
|
+
ReturnType<typeof table.getSortConfig>
|
|
102
|
+
>
|
|
105
103
|
|
|
106
104
|
// Valid: date-range filter accepts DateRangeTableFilter form
|
|
107
105
|
const _loc: Loc = {
|
|
@@ -153,7 +151,10 @@ function testNoFiltersOrSorts() {
|
|
|
153
151
|
|
|
154
152
|
const table = useServerTable(serverTable, { getRowId: (row) => row.id })
|
|
155
153
|
|
|
156
|
-
type Loc = TableLocalization<
|
|
154
|
+
type Loc = TableLocalization<
|
|
155
|
+
ReturnType<typeof table.getFilterConfig>,
|
|
156
|
+
ReturnType<typeof table.getSortConfig>
|
|
157
|
+
>
|
|
157
158
|
|
|
158
159
|
type _EmptyFilters = Expect<Equal<Loc['filters'], {}>>
|
|
159
160
|
type _EmptySorts = Expect<Equal<Loc['sorts'], {}>>
|
package/src/components/tabs.tsx
CHANGED
|
@@ -69,10 +69,7 @@ TabGroup.displayName = 'TabGroup'
|
|
|
69
69
|
|
|
70
70
|
// --- TabList ---
|
|
71
71
|
|
|
72
|
-
const TabListContext = React.createContext<{ color: TabColor; variant: TabVariant }>({
|
|
73
|
-
color: 'primary',
|
|
74
|
-
variant: 'underline'
|
|
75
|
-
})
|
|
72
|
+
const TabListContext = React.createContext<{ color: TabColor; variant: TabVariant }>({ color: 'primary', variant: 'underline' })
|
|
76
73
|
|
|
77
74
|
function TabList({ children, className, color = 'primary', variant = 'underline' }: TabListProps) {
|
|
78
75
|
const containerRef = React.useRef<HTMLDivElement>(null)
|
|
@@ -82,7 +79,11 @@ function TabList({ children, className, color = 'primary', variant = 'underline'
|
|
|
82
79
|
<TabListContext.Provider value={{ color, variant }}>
|
|
83
80
|
<div ref={containerRef} className={tabListContainerClasses[variant]}>
|
|
84
81
|
<AriaTabList className={tw(tabListInnerClasses[variant], className)}>{children}</AriaTabList>
|
|
85
|
-
<div
|
|
82
|
+
<div
|
|
83
|
+
ref={indicatorRef}
|
|
84
|
+
className={getIndicatorClasses(variant, color)}
|
|
85
|
+
style={{ opacity: 0 }}
|
|
86
|
+
/>
|
|
86
87
|
</div>
|
|
87
88
|
</TabListContext.Provider>
|
|
88
89
|
)
|
|
@@ -105,9 +106,7 @@ function TabItem({ children, className, ...props }: TabProps) {
|
|
|
105
106
|
variant === 'oval' ? TAB_OVAL_BASE_CLASSES : TAB_BASE_CLASSES,
|
|
106
107
|
focusClasses,
|
|
107
108
|
isSelected
|
|
108
|
-
? variant === 'oval'
|
|
109
|
-
? TAB_OVAL_SELECTED_CLASSES
|
|
110
|
-
: `${colors.text} font-bold`
|
|
109
|
+
? (variant === 'oval' ? TAB_OVAL_SELECTED_CLASSES : `${colors.text} font-bold`)
|
|
111
110
|
: `${TAB_INACTIVE_CLASSES} data-[hovered]:text-neutral-700`,
|
|
112
111
|
isDisabled && TAB_DISABLED_CLASSES,
|
|
113
112
|
className
|
|
@@ -150,13 +150,7 @@ export function TagField(props: TagFieldProps) {
|
|
|
150
150
|
|
|
151
151
|
<FormFieldComponents.LabelRow label={props.label} cornerHint={props.cornerHint} htmlFor={inputId} />
|
|
152
152
|
|
|
153
|
-
<FormFieldComponents.FieldGroup
|
|
154
|
-
isDisabled={props.isDisabled}
|
|
155
|
-
isInvalid={isInvalid}
|
|
156
|
-
hasWarning={hasWarning}
|
|
157
|
-
shape={props.shape}
|
|
158
|
-
onClick={() => inputRef.current?.focus()}
|
|
159
|
-
>
|
|
153
|
+
<FormFieldComponents.FieldGroup isDisabled={props.isDisabled} isInvalid={isInvalid} hasWarning={hasWarning} shape={props.shape} onClick={() => inputRef.current?.focus()}>
|
|
160
154
|
<div className="flex flex-wrap items-center gap-1.5 px-3 py-1.5 min-h-[38px] w-full">
|
|
161
155
|
{/* Display existing tags */}
|
|
162
156
|
{tags.map((tag, index) =>
|
|
@@ -47,8 +47,6 @@ export type TextFieldProps = {
|
|
|
47
47
|
|
|
48
48
|
export function TextField(props: TextFieldProps) {
|
|
49
49
|
const inputRef = React.useRef<HTMLInputElement>(null)
|
|
50
|
-
const visibleRef = React.useRef<HTMLInputElement>(null)
|
|
51
|
-
|
|
52
50
|
const helpTextId = React.useId()
|
|
53
51
|
const inputId = React.useId()
|
|
54
52
|
|
|
@@ -68,7 +66,7 @@ export function TextField(props: TextFieldProps) {
|
|
|
68
66
|
isRequired: props.isRequired,
|
|
69
67
|
form: props.form,
|
|
70
68
|
focus() {
|
|
71
|
-
|
|
69
|
+
inputRef.current?.focus()
|
|
72
70
|
}
|
|
73
71
|
},
|
|
74
72
|
inputRef
|
|
@@ -115,7 +113,6 @@ export function TextField(props: TextFieldProps) {
|
|
|
115
113
|
inputMode={props.inputMode}
|
|
116
114
|
aria-invalid={isInvalid || undefined}
|
|
117
115
|
aria-describedby={helpTextId}
|
|
118
|
-
ref={visibleRef}
|
|
119
116
|
/>
|
|
120
117
|
{props.trailingInlineAddon}
|
|
121
118
|
</FormFieldComponents.FieldGroup>
|
|
@@ -476,10 +476,7 @@ function getSearchParamsState<L extends QueryStateLoader>(
|
|
|
476
476
|
* Reads from the pending navigation location when one is in flight so the UI
|
|
477
477
|
* reflects optimistic state during transitions.
|
|
478
478
|
*/
|
|
479
|
-
function useState<S>(
|
|
480
|
-
name: string,
|
|
481
|
-
codec: Codec<CodecDef<S>>
|
|
482
|
-
): [S, (val: S | ((prevState: S) => S), navigateOpts?: QueryStateNavigateOptions) => void] {
|
|
479
|
+
function useState<S>(name: string, codec: Codec<CodecDef<S>>): [S, (val: S | ((prevState: S) => S), navigateOpts?: QueryStateNavigateOptions) => void] {
|
|
483
480
|
const [searchParamsRaw, setSearchParams] = useSearchParamsRR()
|
|
484
481
|
const navigation = useNavigation()
|
|
485
482
|
|
|
@@ -46,8 +46,7 @@ export function getIndicatorClasses(variant: TabVariant, color: TabColor): strin
|
|
|
46
46
|
return 'absolute inset-y-1 rounded-md bg-white shadow-sm'
|
|
47
47
|
}
|
|
48
48
|
|
|
49
|
-
export const TAB_OVAL_BASE_CLASSES =
|
|
50
|
-
'relative z-10 px-4 py-1.5 text-sm cursor-default transition-colors duration-200 rounded-md'
|
|
49
|
+
export const TAB_OVAL_BASE_CLASSES = 'relative z-10 px-4 py-1.5 text-sm cursor-default transition-colors duration-200 rounded-md'
|
|
51
50
|
export const TAB_OVAL_SELECTED_CLASSES = 'text-neutral-900 font-semibold'
|
|
52
51
|
|
|
53
52
|
// --- Animated Indicator Hook ---
|