@maestro-js/components 1.0.0-alpha.21 → 1.0.0-alpha.23

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/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.21"
11
+ "@maestro-js/form": "1.0.0-alpha.23"
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.21"
29
+ "@maestro-js/form": "1.0.0-alpha.23"
30
30
  },
31
- "version": "1.0.0-alpha.21",
31
+ "version": "1.0.0-alpha.23",
32
32
  "license": "UNLICENSED",
33
33
  "engines": {
34
34
  "node": ">=22.18.0"
@@ -100,7 +100,10 @@ function AlertDialog_({
100
100
  'data-[exiting]:scale-95 data-[exiting]:opacity-0 data-[exiting]:translate-y-2'
101
101
  )}
102
102
  >
103
- <Dialog className={tw('outline-none bg-white rounded-xl shadow-xl ring-1 ring-black/5 w-full', className)} role="alertdialog">
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
+ >
104
107
  {({ close }) => (
105
108
  <AlertDialogContext.Provider value={{ close }}>
106
109
  <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 ? first[0] ?? '' : `${first[0] ?? ''}${last?.[0] ?? ''}`
51
+ const initials = names.length === 1 ? (first[0] ?? '') : `${first[0] ?? ''}${last?.[0] ?? ''}`
52
52
 
53
53
  return initials.toUpperCase()
54
54
  }
@@ -92,11 +92,7 @@ function DisclosureHeader({
92
92
  />
93
93
  <span
94
94
  className={tw(
95
- size === 'lg'
96
- ? 'text-lg font-semibold'
97
- : size === 'md'
98
- ? 'text-base font-medium'
99
- : 'text-sm font-medium',
95
+ size === 'lg' ? 'text-lg font-semibold' : size === 'md' ? 'text-base font-medium' : 'text-sm font-medium',
100
96
  isDisabled ? 'text-neutral-400' : 'text-neutral-700'
101
97
  )}
102
98
  >
@@ -76,34 +76,32 @@ type FieldGroupProps = {
76
76
  onClick?: React.MouseEventHandler<HTMLDivElement>
77
77
  }
78
78
 
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'
79
+ const FieldGroup = React.forwardRef<HTMLDivElement, FieldGroupProps>(({ children, className, onClick, ...opts }, ref) => {
80
+ const disabled = opts.isDisabled || opts.isReadonly
81
+ const shape = opts.shape === 'oval' ? 'rounded-full' : 'rounded'
83
82
 
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
- )
83
+ return (
84
+ <Group
85
+ ref={ref}
86
+ className={tw(
87
+ 'relative overflow-hidden ring-1 shadow-sm transition-all duration-200 max-w-96',
88
+ 'focus-within:outline-2 focus-within:-outline-offset-1',
89
+ shape,
90
+ disabled && 'ring-neutral-200 bg-neutral-50 text-neutral-400 shadow-none cursor-not-allowed',
91
+ opts.isInvalid && 'ring-negative-300 bg-negative-50 focus-within:outline-negative-500',
92
+ opts.hasWarning && 'ring-notice-300 bg-notice-50 focus-within:outline-notice-500',
93
+ !opts.isInvalid &&
94
+ !opts.hasWarning &&
95
+ !disabled &&
96
+ 'ring-black/10 hover:ring-black/20 focus-within:outline-primary-500',
97
+ className
98
+ )}
99
+ onClick={onClick}
100
+ >
101
+ {children}
102
+ </Group>
103
+ )
104
+ })
107
105
 
108
106
  const FieldInput = React.forwardRef<HTMLInputElement, InputProps>((props, ref) => {
109
107
  return (
@@ -36,7 +36,10 @@ export type LinkTabProps = {
36
36
 
37
37
  // --- LinkTabList ---
38
38
 
39
- const LinkTabListContext = React.createContext<{ color: TabColor; variant: TabVariant }>({ color: 'primary', variant: 'underline' })
39
+ const LinkTabListContext = React.createContext<{ color: TabColor; variant: TabVariant }>({
40
+ color: 'primary',
41
+ variant: 'underline'
42
+ })
40
43
 
41
44
  function LinkTabList({ children, className, color = 'primary', variant = 'underline' }: LinkTabListProps) {
42
45
  const containerRef = React.useRef<HTMLDivElement>(null)
@@ -48,11 +51,7 @@ function LinkTabList({ children, className, color = 'primary', variant = 'underl
48
51
  <div role="tablist" className={tw(tabListInnerClasses[variant], className)}>
49
52
  {children}
50
53
  </div>
51
- <div
52
- ref={indicatorRef}
53
- className={getIndicatorClasses(variant, color)}
54
- style={{ opacity: 0 }}
55
- />
54
+ <div ref={indicatorRef} className={getIndicatorClasses(variant, color)} style={{ opacity: 0 }} />
56
55
  </div>
57
56
  </LinkTabListContext.Provider>
58
57
  )
@@ -73,13 +72,7 @@ function LinkTab({ to, children, className, disabled, replace, end }: LinkTabPro
73
72
  <span
74
73
  role="tab"
75
74
  aria-disabled="true"
76
- className={tw(
77
- baseClasses,
78
- 'outline-none',
79
- TAB_INACTIVE_CLASSES,
80
- TAB_DISABLED_CLASSES,
81
- className
82
- )}
75
+ className={tw(baseClasses, 'outline-none', TAB_INACTIVE_CLASSES, TAB_DISABLED_CLASSES, className)}
83
76
  >
84
77
  {children}
85
78
  </span>
@@ -97,7 +90,9 @@ function LinkTab({ to, children, className, disabled, replace, end }: LinkTabPro
97
90
  baseClasses,
98
91
  focusClasses,
99
92
  isActive
100
- ? (variant === 'oval' ? TAB_OVAL_SELECTED_CLASSES : `${colors.text} font-bold`)
93
+ ? variant === 'oval'
94
+ ? TAB_OVAL_SELECTED_CLASSES
95
+ : `${colors.text} font-bold`
101
96
  : `${TAB_INACTIVE_CLASSES} hover:text-neutral-700`,
102
97
  className
103
98
  )
@@ -162,7 +162,9 @@ 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 && <p className="text-xs text-neutral-500">{formatFileSize(fileItem.file.size)}</p>}
165
+ {fileItem.file && (
166
+ <p className="text-xs text-neutral-500">{formatFileSize(fileItem.file.size)}</p>
167
+ )}
166
168
  </div>
167
169
  </div>
168
170
  {!props.isDisabled && !props.isReadonly && (
@@ -180,7 +180,13 @@ export function NumericTagField(props: NumericTagFieldProps) {
180
180
 
181
181
  <FormFieldComponents.LabelRow label={props.label} cornerHint={props.cornerHint} htmlFor={inputId} />
182
182
 
183
- <FormFieldComponents.FieldGroup isDisabled={props.isDisabled} isInvalid={isInvalid} hasWarning={hasWarning} shape={props.shape} onClick={() => inputRef.current?.focus()}>
183
+ <FormFieldComponents.FieldGroup
184
+ isDisabled={props.isDisabled}
185
+ isInvalid={isInvalid}
186
+ hasWarning={hasWarning}
187
+ shape={props.shape}
188
+ onClick={() => inputRef.current?.focus()}
189
+ >
184
190
  <div className="flex flex-wrap items-center gap-1.5 px-3 py-1.5 min-h-[38px] w-full">
185
191
  {/* Display existing tags */}
186
192
  {tags.map((tag, index) => (
@@ -28,7 +28,10 @@ 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: [{ label: 'Active', value: 'active' }, { label: 'Inactive', value: 'inactive' }]
31
+ options: [
32
+ { label: 'Active', value: 'active' },
33
+ { label: 'Inactive', value: 'inactive' }
34
+ ]
32
35
  }
33
36
 
34
37
  // Date range → DateRangeTableFilter (type: 'date-range', no value-typed options)
@@ -67,10 +67,7 @@ function testLocalizationWithSelectFilter() {
67
67
  }
68
68
  })
69
69
 
70
- type Loc = TableLocalization<
71
- ReturnType<typeof table.getFilterConfig>,
72
- ReturnType<typeof table.getSortConfig>
73
- >
70
+ type Loc = TableLocalization<ReturnType<typeof table.getFilterConfig>, ReturnType<typeof table.getSortConfig>>
74
71
 
75
72
  type _LocFilterKeys = Expect<Equal<keyof Loc['filters'], 'status'>>
76
73
  type _LocSortKeys = Expect<Equal<keyof Loc['sorts'], 'newest' | 'oldest'>>
@@ -111,10 +108,7 @@ function testLocalizationWithDateRangeFilter() {
111
108
  }
112
109
  })
113
110
 
114
- type Loc = TableLocalization<
115
- ReturnType<typeof table.getFilterConfig>,
116
- ReturnType<typeof table.getSortConfig>
117
- >
111
+ type Loc = TableLocalization<ReturnType<typeof table.getFilterConfig>, ReturnType<typeof table.getSortConfig>>
118
112
 
119
113
  // Valid: date-range filter accepts DateRangeTableFilter form
120
114
  const _loc: Loc = {
@@ -207,10 +201,7 @@ function testNoFiltersOrSorts() {
207
201
  getRowId: (row) => row.id
208
202
  })
209
203
 
210
- type Loc = TableLocalization<
211
- ReturnType<typeof table.getFilterConfig>,
212
- ReturnType<typeof table.getSortConfig>
213
- >
204
+ type Loc = TableLocalization<ReturnType<typeof table.getFilterConfig>, ReturnType<typeof table.getSortConfig>>
214
205
 
215
206
  type _EmptyFilters = Expect<Equal<Loc['filters'], {}>>
216
207
  type _EmptySorts = Expect<Equal<Loc['sorts'], {}>>
@@ -26,7 +26,11 @@ type Row = {
26
26
  // =============================================================================
27
27
 
28
28
  function testFilterAndSortInference() {
29
- const serverTable = null as unknown as ServerTable.ServerTable<Row, { status: 'active' | 'inactive' }, { newest: true; oldest: true }>
29
+ const serverTable = null as unknown as ServerTable.ServerTable<
30
+ Row,
31
+ { status: 'active' | 'inactive' },
32
+ { newest: true; oldest: true }
33
+ >
30
34
 
31
35
  const table = useServerTable(serverTable, { getRowId: (row) => row.id })
32
36
 
@@ -48,14 +52,15 @@ function testFilterAndSortInference() {
48
52
  // =============================================================================
49
53
 
50
54
  function testLocalizationWithSelectFilter() {
51
- const serverTable = null as unknown as ServerTable.ServerTable<Row, { status: 'active' | 'inactive' }, { newest: true; oldest: true }>
55
+ const serverTable = null as unknown as ServerTable.ServerTable<
56
+ Row,
57
+ { status: 'active' | 'inactive' },
58
+ { newest: true; oldest: true }
59
+ >
52
60
 
53
61
  const table = useServerTable(serverTable, { getRowId: (row) => row.id })
54
62
 
55
- type Loc = TableLocalization<
56
- ReturnType<typeof table.getFilterConfig>,
57
- ReturnType<typeof table.getSortConfig>
58
- >
63
+ type Loc = TableLocalization<ReturnType<typeof table.getFilterConfig>, ReturnType<typeof table.getSortConfig>>
59
64
 
60
65
  type _LocFilterKeys = Expect<Equal<keyof Loc['filters'], 'status'>>
61
66
  type _LocSortKeys = Expect<Equal<keyof Loc['sorts'], 'newest' | 'oldest'>>
@@ -96,10 +101,7 @@ function testLocalizationWithDateRangeFilter() {
96
101
 
97
102
  const table = useServerTable(serverTable, { getRowId: (row) => row.id })
98
103
 
99
- type Loc = TableLocalization<
100
- ReturnType<typeof table.getFilterConfig>,
101
- ReturnType<typeof table.getSortConfig>
102
- >
104
+ type Loc = TableLocalization<ReturnType<typeof table.getFilterConfig>, ReturnType<typeof table.getSortConfig>>
103
105
 
104
106
  // Valid: date-range filter accepts DateRangeTableFilter form
105
107
  const _loc: Loc = {
@@ -151,10 +153,7 @@ function testNoFiltersOrSorts() {
151
153
 
152
154
  const table = useServerTable(serverTable, { getRowId: (row) => row.id })
153
155
 
154
- type Loc = TableLocalization<
155
- ReturnType<typeof table.getFilterConfig>,
156
- ReturnType<typeof table.getSortConfig>
157
- >
156
+ type Loc = TableLocalization<ReturnType<typeof table.getFilterConfig>, ReturnType<typeof table.getSortConfig>>
158
157
 
159
158
  type _EmptyFilters = Expect<Equal<Loc['filters'], {}>>
160
159
  type _EmptySorts = Expect<Equal<Loc['sorts'], {}>>
@@ -69,7 +69,10 @@ TabGroup.displayName = 'TabGroup'
69
69
 
70
70
  // --- TabList ---
71
71
 
72
- const TabListContext = React.createContext<{ color: TabColor; variant: TabVariant }>({ color: 'primary', variant: 'underline' })
72
+ const TabListContext = React.createContext<{ color: TabColor; variant: TabVariant }>({
73
+ color: 'primary',
74
+ variant: 'underline'
75
+ })
73
76
 
74
77
  function TabList({ children, className, color = 'primary', variant = 'underline' }: TabListProps) {
75
78
  const containerRef = React.useRef<HTMLDivElement>(null)
@@ -79,11 +82,7 @@ function TabList({ children, className, color = 'primary', variant = 'underline'
79
82
  <TabListContext.Provider value={{ color, variant }}>
80
83
  <div ref={containerRef} className={tabListContainerClasses[variant]}>
81
84
  <AriaTabList className={tw(tabListInnerClasses[variant], className)}>{children}</AriaTabList>
82
- <div
83
- ref={indicatorRef}
84
- className={getIndicatorClasses(variant, color)}
85
- style={{ opacity: 0 }}
86
- />
85
+ <div ref={indicatorRef} className={getIndicatorClasses(variant, color)} style={{ opacity: 0 }} />
87
86
  </div>
88
87
  </TabListContext.Provider>
89
88
  )
@@ -106,7 +105,9 @@ function TabItem({ children, className, ...props }: TabProps) {
106
105
  variant === 'oval' ? TAB_OVAL_BASE_CLASSES : TAB_BASE_CLASSES,
107
106
  focusClasses,
108
107
  isSelected
109
- ? (variant === 'oval' ? TAB_OVAL_SELECTED_CLASSES : `${colors.text} font-bold`)
108
+ ? variant === 'oval'
109
+ ? TAB_OVAL_SELECTED_CLASSES
110
+ : `${colors.text} font-bold`
110
111
  : `${TAB_INACTIVE_CLASSES} data-[hovered]:text-neutral-700`,
111
112
  isDisabled && TAB_DISABLED_CLASSES,
112
113
  className
@@ -150,7 +150,13 @@ export function TagField(props: TagFieldProps) {
150
150
 
151
151
  <FormFieldComponents.LabelRow label={props.label} cornerHint={props.cornerHint} htmlFor={inputId} />
152
152
 
153
- <FormFieldComponents.FieldGroup isDisabled={props.isDisabled} isInvalid={isInvalid} hasWarning={hasWarning} shape={props.shape} onClick={() => inputRef.current?.focus()}>
153
+ <FormFieldComponents.FieldGroup
154
+ isDisabled={props.isDisabled}
155
+ isInvalid={isInvalid}
156
+ hasWarning={hasWarning}
157
+ shape={props.shape}
158
+ onClick={() => inputRef.current?.focus()}
159
+ >
154
160
  <div className="flex flex-wrap items-center gap-1.5 px-3 py-1.5 min-h-[38px] w-full">
155
161
  {/* Display existing tags */}
156
162
  {tags.map((tag, index) =>
@@ -476,7 +476,10 @@ 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>(name: string, codec: Codec<CodecDef<S>>): [S, (val: S | ((prevState: S) => S), navigateOpts?: QueryStateNavigateOptions) => void] {
479
+ function useState<S>(
480
+ name: string,
481
+ codec: Codec<CodecDef<S>>
482
+ ): [S, (val: S | ((prevState: S) => S), navigateOpts?: QueryStateNavigateOptions) => void] {
480
483
  const [searchParamsRaw, setSearchParams] = useSearchParamsRR()
481
484
  const navigation = useNavigation()
482
485
 
@@ -46,7 +46,8 @@ 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 = '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 =
50
+ 'relative z-10 px-4 py-1.5 text-sm cursor-default transition-colors duration-200 rounded-md'
50
51
  export const TAB_OVAL_SELECTED_CLASSES = 'text-neutral-900 font-semibold'
51
52
 
52
53
  // --- Animated Indicator Hook ---