fermmap-shared 0.1.0
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/LICENSE +21 -0
- package/README.md +180 -0
- package/dist/main.cjs +2907 -0
- package/dist/main.cjs.map +1 -0
- package/dist/main.css +1388 -0
- package/dist/main.css.map +1 -0
- package/dist/module.css +1388 -0
- package/dist/module.css.map +1 -0
- package/dist/module.mjs +2899 -0
- package/dist/module.mjs.map +1 -0
- package/dist/types.d.ts +693 -0
- package/dist/types.d.ts.map +1 -0
- package/package.json +73 -0
- package/src/components/Checkbox.css +22 -0
- package/src/components/DisclosureGroup.css +37 -0
- package/src/components/ProgressBar.css +18 -0
- package/src/styles/variables.css +77 -0
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,693 @@
|
|
|
1
|
+
import { ButtonProps as _ButtonProps1, TextFieldProps as _TextFieldProps1, Selection, CheckboxProps as _CheckboxProps1, Key, SortDescriptor, DisclosureGroupProps, LinkProps, RadioGroupProps as _RadioGroupProps1, SelectProps, SwitchProps as _SwitchProps1, TabListProps, TabPanelProps, TabProps, TabsProps } from "react-aria-components";
|
|
2
|
+
import { JSX } from "react/jsx-runtime";
|
|
3
|
+
import { ReactNode } from "react";
|
|
4
|
+
interface ButtonProps extends _ButtonProps1 {
|
|
5
|
+
children?: React.ReactNode;
|
|
6
|
+
variant?: 'primary' | 'secondary' | 'danger' | 'navigation';
|
|
7
|
+
size?: 'S' | 'M' | 'L';
|
|
8
|
+
}
|
|
9
|
+
export const Button: ({ children, variant, size, className, ...props }: ButtonProps) => JSX.Element;
|
|
10
|
+
export const textFieldInputStyles: () => {
|
|
11
|
+
readonly padding: 12;
|
|
12
|
+
readonly paddingX: 16;
|
|
13
|
+
readonly borderWidth: 1;
|
|
14
|
+
readonly borderStyle: "solid";
|
|
15
|
+
readonly borderColor: {
|
|
16
|
+
readonly default: "--plum-300";
|
|
17
|
+
readonly isHovered: "--plum-400";
|
|
18
|
+
readonly isFocusVisible: "--plum-500";
|
|
19
|
+
readonly isInvalid: "--berry-500";
|
|
20
|
+
};
|
|
21
|
+
readonly borderRadius: "lg";
|
|
22
|
+
readonly font: "body";
|
|
23
|
+
readonly backgroundColor: "layer-1";
|
|
24
|
+
readonly color: "neutral";
|
|
25
|
+
readonly outline: "none";
|
|
26
|
+
};
|
|
27
|
+
interface TextFieldProps extends Omit<_TextFieldProps1, 'children'> {
|
|
28
|
+
label: string;
|
|
29
|
+
type?: 'text' | 'password' | 'email' | 'tel' | 'url' | 'number';
|
|
30
|
+
error?: string;
|
|
31
|
+
description?: string;
|
|
32
|
+
placeholder?: string;
|
|
33
|
+
}
|
|
34
|
+
export function TextField({ label, type, error, description, placeholder, ...props }: TextFieldProps): JSX.Element;
|
|
35
|
+
interface AlertDialogProps {
|
|
36
|
+
isOpen: boolean;
|
|
37
|
+
onClose: () => void;
|
|
38
|
+
title: string;
|
|
39
|
+
message: string;
|
|
40
|
+
variant?: 'danger' | 'warning' | 'info' | 'success';
|
|
41
|
+
confirmLabel?: string;
|
|
42
|
+
cancelLabel?: string;
|
|
43
|
+
onConfirm: () => void | Promise<void>;
|
|
44
|
+
showCancel?: boolean;
|
|
45
|
+
children?: React.ReactNode;
|
|
46
|
+
}
|
|
47
|
+
export function AlertDialog({ isOpen, onClose, title, message, variant, confirmLabel, cancelLabel, onConfirm, showCancel, children }: AlertDialogProps): JSX.Element;
|
|
48
|
+
interface PromptDialogProps {
|
|
49
|
+
isOpen: boolean;
|
|
50
|
+
onClose: () => void;
|
|
51
|
+
title: string;
|
|
52
|
+
message: string;
|
|
53
|
+
inputLabel: string;
|
|
54
|
+
inputPlaceholder?: string;
|
|
55
|
+
confirmLabel?: string;
|
|
56
|
+
cancelLabel?: string;
|
|
57
|
+
onConfirm: (value: string) => void | Promise<void>;
|
|
58
|
+
validator?: (value: string) => string | null;
|
|
59
|
+
}
|
|
60
|
+
export function PromptDialog({ isOpen, onClose, title, message, inputLabel, inputPlaceholder, confirmLabel, cancelLabel, onConfirm, validator }: PromptDialogProps): JSX.Element;
|
|
61
|
+
export interface AutocompleteItem {
|
|
62
|
+
id: string | number;
|
|
63
|
+
name: string;
|
|
64
|
+
[key: string]: any;
|
|
65
|
+
}
|
|
66
|
+
export interface AutocompleteProps<T extends AutocompleteItem> {
|
|
67
|
+
items: T[];
|
|
68
|
+
selectedKeys?: Selection;
|
|
69
|
+
onSelectionChange?: (keys: Selection) => void;
|
|
70
|
+
selectionMode?: 'none' | 'single' | 'multiple';
|
|
71
|
+
label: string;
|
|
72
|
+
placeholder?: string;
|
|
73
|
+
ariaLabel?: string;
|
|
74
|
+
error?: string;
|
|
75
|
+
getItemText?: (item: T) => string;
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* Autocomplete component using React Aria SearchField + ListBox
|
|
79
|
+
*
|
|
80
|
+
* Features:
|
|
81
|
+
* - SearchField for filtering items
|
|
82
|
+
* - Optional checkboxes for multi-selection
|
|
83
|
+
* - Shows both selected and unselected items when filtered
|
|
84
|
+
* - Selected items highlighted with background color
|
|
85
|
+
* - Keyboard navigation (arrow keys, enter, escape)
|
|
86
|
+
* - Accessible (ARIA labels, focus management)
|
|
87
|
+
*
|
|
88
|
+
* @example
|
|
89
|
+
* ```tsx
|
|
90
|
+
* // Single select
|
|
91
|
+
* <Autocomplete
|
|
92
|
+
* items={sources}
|
|
93
|
+
* selectedKeys={selectedKey}
|
|
94
|
+
* onSelectionChange={setSelectedKey}
|
|
95
|
+
* selectionMode="single"
|
|
96
|
+
* label="Select Source"
|
|
97
|
+
* placeholder="Search sources..."
|
|
98
|
+
* />
|
|
99
|
+
*
|
|
100
|
+
* // Multi select
|
|
101
|
+
* <Autocomplete
|
|
102
|
+
* items={sources}
|
|
103
|
+
* selectedKeys={selectedKeys}
|
|
104
|
+
* onSelectionChange={setSelectedKeys}
|
|
105
|
+
* selectionMode="multiple"
|
|
106
|
+
* label="Select Sources"
|
|
107
|
+
* placeholder="Search sources..."
|
|
108
|
+
* />
|
|
109
|
+
*
|
|
110
|
+
* // No selection (just filtering)
|
|
111
|
+
* <Autocomplete
|
|
112
|
+
* items={sources}
|
|
113
|
+
* selectionMode="none"
|
|
114
|
+
* label="Search Sources"
|
|
115
|
+
* placeholder="Search sources..."
|
|
116
|
+
* />
|
|
117
|
+
* ```
|
|
118
|
+
*/
|
|
119
|
+
export function Autocomplete<T extends AutocompleteItem>({ items, selectedKeys, onSelectionChange, selectionMode, label, placeholder, ariaLabel, error, getItemText, }: AutocompleteProps<T>): JSX.Element;
|
|
120
|
+
export interface CheckboxProps extends Omit<_CheckboxProps1, 'className' | 'style'> {
|
|
121
|
+
/**
|
|
122
|
+
* The size of the Checkbox.
|
|
123
|
+
* @default 'M'
|
|
124
|
+
*/
|
|
125
|
+
size?: 'S' | 'M' | 'L';
|
|
126
|
+
}
|
|
127
|
+
/**
|
|
128
|
+
* Checkbox component for selection within tables and forms.
|
|
129
|
+
* Simplified version based on React Spectrum S2 Checkbox.
|
|
130
|
+
*
|
|
131
|
+
* @example
|
|
132
|
+
* ```tsx
|
|
133
|
+
* <Checkbox isSelected={selected} onChange={setSelected}>
|
|
134
|
+
* Subscribe to newsletter
|
|
135
|
+
* </Checkbox>
|
|
136
|
+
*
|
|
137
|
+
* // In table header/cell (no label)
|
|
138
|
+
* <Checkbox slot="selection" />
|
|
139
|
+
* ```
|
|
140
|
+
*/
|
|
141
|
+
export function Checkbox({ size, children, ...props }: CheckboxProps): JSX.Element;
|
|
142
|
+
interface ProgressBarProps {
|
|
143
|
+
label?: string;
|
|
144
|
+
value?: number;
|
|
145
|
+
maxValue?: number;
|
|
146
|
+
isIndeterminate?: boolean;
|
|
147
|
+
showValueLabel?: boolean;
|
|
148
|
+
'aria-label'?: string;
|
|
149
|
+
}
|
|
150
|
+
/**
|
|
151
|
+
* ProgressBar Component
|
|
152
|
+
*
|
|
153
|
+
* Accessible progress indicator using React Aria Components.
|
|
154
|
+
* Supports both determinate (with value) and indeterminate (loading) states.
|
|
155
|
+
*
|
|
156
|
+
* @example
|
|
157
|
+
* // Determinate progress
|
|
158
|
+
* <ProgressBar label="Loading..." value={50} maxValue={100} />
|
|
159
|
+
*
|
|
160
|
+
* @example
|
|
161
|
+
* // Indeterminate progress
|
|
162
|
+
* <ProgressBar label="Loading..." isIndeterminate />
|
|
163
|
+
*/
|
|
164
|
+
export function ProgressBar({ label, value, maxValue, isIndeterminate, showValueLabel, 'aria-label': ariaLabel, }: ProgressBarProps): JSX.Element;
|
|
165
|
+
export interface ColumnDef<T> {
|
|
166
|
+
key: string;
|
|
167
|
+
label: string;
|
|
168
|
+
renderCell: (item: T) => ReactNode;
|
|
169
|
+
width?: string;
|
|
170
|
+
isRowHeader?: boolean;
|
|
171
|
+
align?: 'start' | 'center' | 'end';
|
|
172
|
+
}
|
|
173
|
+
export interface TableProps<T> {
|
|
174
|
+
data: T[];
|
|
175
|
+
columns: ColumnDef<T>[];
|
|
176
|
+
onRowAction?: (key: Key) => void;
|
|
177
|
+
ariaLabel: string;
|
|
178
|
+
sortDescriptor?: SortDescriptor;
|
|
179
|
+
onSortChange?: (descriptor: SortDescriptor) => void;
|
|
180
|
+
selectionMode?: 'none' | 'single' | 'multiple';
|
|
181
|
+
selectedKeys?: Set<Key>;
|
|
182
|
+
onSelectionChange?: (keys: Set<Key>) => void;
|
|
183
|
+
onLoadMore?: () => void;
|
|
184
|
+
isLoadingMore?: boolean;
|
|
185
|
+
}
|
|
186
|
+
/**
|
|
187
|
+
* Reusable Table component using React Aria Components
|
|
188
|
+
*
|
|
189
|
+
* Features:
|
|
190
|
+
* - Collection-based API for better performance
|
|
191
|
+
* - Built-in virtualization support (via RAC)
|
|
192
|
+
* - Keyboard navigation
|
|
193
|
+
* - Screen reader support
|
|
194
|
+
* - Optional sorting
|
|
195
|
+
* - Optional row selection
|
|
196
|
+
* - Optional row actions (clickable rows)
|
|
197
|
+
* - Checkbox column for multiple selection
|
|
198
|
+
* - Hover and selected states
|
|
199
|
+
*
|
|
200
|
+
* @example
|
|
201
|
+
* ```tsx
|
|
202
|
+
* const columns: ColumnDef<Run>[] = [
|
|
203
|
+
* { key: 'id', label: 'ID', renderCell: (run) => `#${run.id}` },
|
|
204
|
+
* { key: 'status', label: 'Status', renderCell: (run) => <Badge variant={run.status}>{run.status}</Badge> }
|
|
205
|
+
* ];
|
|
206
|
+
*
|
|
207
|
+
* <Table
|
|
208
|
+
* data={runs}
|
|
209
|
+
* columns={columns}
|
|
210
|
+
* ariaLabel="Scraper runs"
|
|
211
|
+
* selectionMode="multiple"
|
|
212
|
+
* selectedKeys={selectedIds}
|
|
213
|
+
* onSelectionChange={setSelectedIds}
|
|
214
|
+
* />
|
|
215
|
+
* ```
|
|
216
|
+
*/
|
|
217
|
+
export function Table<T extends {
|
|
218
|
+
id: number | string;
|
|
219
|
+
}>({ data, columns, onRowAction, ariaLabel, sortDescriptor, onSortChange, selectionMode, selectedKeys, onSelectionChange, onLoadMore, isLoadingMore }: TableProps<T>): JSX.Element;
|
|
220
|
+
export interface AutocompleteTableProps<T extends AutocompleteItem> {
|
|
221
|
+
allItems: T[];
|
|
222
|
+
selectedKeys: Selection;
|
|
223
|
+
onSelectionChange: (keys: Selection) => void;
|
|
224
|
+
selectionMode?: 'single' | 'multiple';
|
|
225
|
+
searchLabel: string;
|
|
226
|
+
searchPlaceholder?: string;
|
|
227
|
+
getItemText?: (item: T) => string;
|
|
228
|
+
columns: ColumnDef<T>[];
|
|
229
|
+
tableLabel: string;
|
|
230
|
+
}
|
|
231
|
+
/**
|
|
232
|
+
* Composite component combining Autocomplete and Table
|
|
233
|
+
* Useful for search-and-select workflows where selected items are displayed in a table
|
|
234
|
+
*
|
|
235
|
+
* Features:
|
|
236
|
+
* - Autocomplete search field at top
|
|
237
|
+
* - Table below showing selected items
|
|
238
|
+
* - Filters all items in autocomplete
|
|
239
|
+
* - Shows only selected items in table
|
|
240
|
+
* - Scrollable table with max height of 384px
|
|
241
|
+
*
|
|
242
|
+
* @example
|
|
243
|
+
* ```tsx
|
|
244
|
+
* <AutocompleteTable
|
|
245
|
+
* allItems={allSources}
|
|
246
|
+
* selectedKeys={selectedSourceIds}
|
|
247
|
+
* onSelectionChange={setSelectedSourceIds}
|
|
248
|
+
* selectionMode="multiple"
|
|
249
|
+
* searchLabel="Search Sources"
|
|
250
|
+
* searchPlaceholder="Search by name or URL..."
|
|
251
|
+
* columns={[
|
|
252
|
+
* { key: 'name', label: 'Name', isRowHeader: true },
|
|
253
|
+
* { key: 'domain', label: 'Domain' },
|
|
254
|
+
* { key: 'actions', label: 'Actions', align: 'end' },
|
|
255
|
+
* ]}
|
|
256
|
+
* tableLabel="Selected Sources"
|
|
257
|
+
* />
|
|
258
|
+
* ```
|
|
259
|
+
*/
|
|
260
|
+
export function AutocompleteTable<T extends AutocompleteItem>({ allItems, selectedKeys, onSelectionChange, selectionMode, searchLabel, searchPlaceholder, getItemText, columns, tableLabel, }: AutocompleteTableProps<T>): JSX.Element;
|
|
261
|
+
export type BadgeVariant = 'completed' | 'running' | 'failed' | 'cancelled' | 'pending' | 'plum' | 'cucumber' | 'berry' | 'ginger' | 'peach';
|
|
262
|
+
interface BadgeProps {
|
|
263
|
+
variant?: BadgeVariant;
|
|
264
|
+
children: React.ReactNode;
|
|
265
|
+
}
|
|
266
|
+
/**
|
|
267
|
+
* Badge component for displaying status or category with conditional colors
|
|
268
|
+
*
|
|
269
|
+
* @example
|
|
270
|
+
* <Badge variant="completed">Completed</Badge>
|
|
271
|
+
* <Badge variant="cucumber">Vegetable</Badge>
|
|
272
|
+
*/
|
|
273
|
+
export function Badge({ variant, children }: BadgeProps): JSX.Element;
|
|
274
|
+
type LocaleMessages = Record<string, Record<string, string>>;
|
|
275
|
+
interface I18nProviderProps {
|
|
276
|
+
children: ReactNode;
|
|
277
|
+
messages: LocaleMessages;
|
|
278
|
+
}
|
|
279
|
+
/**
|
|
280
|
+
* Unified i18n provider that can be used by both frontend and admin UI.
|
|
281
|
+
*
|
|
282
|
+
* @param messages - Locale messages object (e.g., from src/i18n/index.ts or admin-ui/src/i18n/index.ts)
|
|
283
|
+
*
|
|
284
|
+
* @example
|
|
285
|
+
* // Frontend usage
|
|
286
|
+
* import { localeMessages } from '@/i18n';
|
|
287
|
+
* <I18nProvider messages={localeMessages}>{children}</I18nProvider>
|
|
288
|
+
*
|
|
289
|
+
* @example
|
|
290
|
+
* // Admin UI usage
|
|
291
|
+
* import { localeMessages } from '@admin/i18n';
|
|
292
|
+
* <I18nProvider messages={localeMessages}>{children}</I18nProvider>
|
|
293
|
+
*/
|
|
294
|
+
export function I18nProvider({ children, messages }: I18nProviderProps): JSX.Element;
|
|
295
|
+
interface CloseButtonProps extends Omit<_ButtonProps1, 'onPress'> {
|
|
296
|
+
onClose: () => void;
|
|
297
|
+
}
|
|
298
|
+
export const CloseButton: ({ onClose, ...props }: CloseButtonProps) => JSX.Element;
|
|
299
|
+
export interface ComboBoxItem {
|
|
300
|
+
id: Key;
|
|
301
|
+
label: string;
|
|
302
|
+
textValue?: string;
|
|
303
|
+
}
|
|
304
|
+
export interface ComboBoxProps {
|
|
305
|
+
label?: string;
|
|
306
|
+
description?: string;
|
|
307
|
+
errorMessage?: string;
|
|
308
|
+
isRequired?: boolean;
|
|
309
|
+
isDisabled?: boolean;
|
|
310
|
+
selectedKey?: Key | null;
|
|
311
|
+
onSelectionChange?: (key: Key | null) => void;
|
|
312
|
+
items: ComboBoxItem[];
|
|
313
|
+
placeholder?: string;
|
|
314
|
+
'aria-label'?: string;
|
|
315
|
+
inputValue?: string;
|
|
316
|
+
onInputChange?: (value: string) => void;
|
|
317
|
+
}
|
|
318
|
+
/**
|
|
319
|
+
* Generic ComboBox component for searchable single-selection.
|
|
320
|
+
*
|
|
321
|
+
* Uses React Aria Components ComboBox for accessible selection with filtering.
|
|
322
|
+
* Reusable for any data type - countries, users, categories, etc.
|
|
323
|
+
*
|
|
324
|
+
* @example
|
|
325
|
+
* ```tsx
|
|
326
|
+
* const items = [
|
|
327
|
+
* { id: 1, label: 'Apple' },
|
|
328
|
+
* { id: 2, label: 'Banana' },
|
|
329
|
+
* { id: 3, label: 'Orange' },
|
|
330
|
+
* ];
|
|
331
|
+
*
|
|
332
|
+
* <ComboBox
|
|
333
|
+
* label="Fruit"
|
|
334
|
+
* items={items}
|
|
335
|
+
* selectedKey={selectedId}
|
|
336
|
+
* onSelectionChange={setSelectedId}
|
|
337
|
+
* placeholder="Select a fruit"
|
|
338
|
+
* />
|
|
339
|
+
* ```
|
|
340
|
+
*/
|
|
341
|
+
export function ComboBox({ label, description, errorMessage, isRequired, isDisabled, selectedKey, onSelectionChange, items, placeholder, 'aria-label': ariaLabel, inputValue: controlledInputValue, onInputChange: controlledOnInputChange, }: ComboBoxProps): JSX.Element;
|
|
342
|
+
export interface DisclosureItem {
|
|
343
|
+
id: string;
|
|
344
|
+
title: string;
|
|
345
|
+
content: React.ReactNode;
|
|
346
|
+
onPress?: () => void;
|
|
347
|
+
}
|
|
348
|
+
interface CustomDisclosureGroupProps extends Omit<DisclosureGroupProps, 'children'> {
|
|
349
|
+
items: DisclosureItem[];
|
|
350
|
+
'aria-label'?: string;
|
|
351
|
+
}
|
|
352
|
+
/**
|
|
353
|
+
* Reusable DisclosureGroup component
|
|
354
|
+
* Displays collapsible sections with consistent styling
|
|
355
|
+
*
|
|
356
|
+
* @example
|
|
357
|
+
* <DisclosureGroup
|
|
358
|
+
* items={[
|
|
359
|
+
* {
|
|
360
|
+
* id: 'section1',
|
|
361
|
+
* title: 'Section 1',
|
|
362
|
+
* content: <div>Content goes here</div>
|
|
363
|
+
* }
|
|
364
|
+
* ]}
|
|
365
|
+
* />
|
|
366
|
+
*/
|
|
367
|
+
export function DisclosureGroup({ items, ...props }: CustomDisclosureGroupProps): JSX.Element;
|
|
368
|
+
interface FilterOption {
|
|
369
|
+
value: string;
|
|
370
|
+
label: string;
|
|
371
|
+
}
|
|
372
|
+
interface FilterTabsProps {
|
|
373
|
+
value: string;
|
|
374
|
+
onChange: (value: string) => void;
|
|
375
|
+
options: FilterOption[];
|
|
376
|
+
ariaLabel?: string;
|
|
377
|
+
}
|
|
378
|
+
/**
|
|
379
|
+
* FilterTabs component for status filtering
|
|
380
|
+
* Uses React Aria ToggleButtonGroup with SelectionIndicator
|
|
381
|
+
*
|
|
382
|
+
* @example
|
|
383
|
+
* <FilterTabs
|
|
384
|
+
* value={statusFilter}
|
|
385
|
+
* onChange={setStatusFilter}
|
|
386
|
+
* options={[
|
|
387
|
+
* { value: 'all', label: 'All' },
|
|
388
|
+
* { value: 'running', label: 'Running' }
|
|
389
|
+
* ]}
|
|
390
|
+
* ariaLabel="Filter by status"
|
|
391
|
+
* />
|
|
392
|
+
*/
|
|
393
|
+
export function FilterTabs({ value, onChange, options, ariaLabel }: FilterTabsProps): JSX.Element;
|
|
394
|
+
interface LabeledValueProps {
|
|
395
|
+
label: string;
|
|
396
|
+
error?: string;
|
|
397
|
+
description?: string;
|
|
398
|
+
children: React.ReactNode;
|
|
399
|
+
}
|
|
400
|
+
export function LabeledValue({ label, children, error, description, ...props }: LabeledValueProps): JSX.Element;
|
|
401
|
+
interface CustomLinkProps extends Omit<LinkProps, 'className'> {
|
|
402
|
+
children: ReactNode;
|
|
403
|
+
isExternal?: boolean;
|
|
404
|
+
className?: string | ((renderProps: any) => string);
|
|
405
|
+
}
|
|
406
|
+
/**
|
|
407
|
+
* Link Component
|
|
408
|
+
*
|
|
409
|
+
* Wraps React Aria Components Link with S2 styling and proper a11y.
|
|
410
|
+
* Automatically handles focus states and keyboard navigation.
|
|
411
|
+
* External links automatically get target="_blank" and rel="noopener noreferrer".
|
|
412
|
+
*
|
|
413
|
+
* @example
|
|
414
|
+
* <Link href="/ferments">Browse Ferments</Link>
|
|
415
|
+
*
|
|
416
|
+
* @example
|
|
417
|
+
* <Link href="https://example.com" isExternal>External Link</Link>
|
|
418
|
+
*
|
|
419
|
+
* @example
|
|
420
|
+
* <Link href="/" className={customStyles}>Custom Styled Link</Link>
|
|
421
|
+
*/
|
|
422
|
+
export function Link({ children, href, isExternal, className, ...props }: CustomLinkProps): JSX.Element;
|
|
423
|
+
interface RadioGroupProps extends Omit<_RadioGroupProps1, 'children'> {
|
|
424
|
+
label: string;
|
|
425
|
+
options: Array<{
|
|
426
|
+
id: string;
|
|
427
|
+
label: string;
|
|
428
|
+
value: string;
|
|
429
|
+
}>;
|
|
430
|
+
error?: string;
|
|
431
|
+
}
|
|
432
|
+
export function RadioGroup({ label, options, error, ...props }: RadioGroupProps): JSX.Element;
|
|
433
|
+
interface SearchFieldProps {
|
|
434
|
+
value: string;
|
|
435
|
+
onChange: (value: string) => void;
|
|
436
|
+
label: string;
|
|
437
|
+
placeholder: string;
|
|
438
|
+
ariaLabel: string;
|
|
439
|
+
}
|
|
440
|
+
/**
|
|
441
|
+
* Reusable SearchField component using React Aria Components
|
|
442
|
+
* Styled with S2 design tokens and includes search icon
|
|
443
|
+
*
|
|
444
|
+
* @example
|
|
445
|
+
* <SearchField
|
|
446
|
+
* value={searchQuery}
|
|
447
|
+
* onChange={setSearchTerm}
|
|
448
|
+
* label="Search"
|
|
449
|
+
* placeholder="Search ferments..."
|
|
450
|
+
* ariaLabel="Search ferments by name or description"
|
|
451
|
+
* />
|
|
452
|
+
*/
|
|
453
|
+
export function SearchField({ value, onChange, label, placeholder, ariaLabel, }: SearchFieldProps): JSX.Element;
|
|
454
|
+
interface SegmentedControlProps {
|
|
455
|
+
value: 'map' | 'list';
|
|
456
|
+
}
|
|
457
|
+
/**
|
|
458
|
+
* SegmentedControl for Map/List view toggle
|
|
459
|
+
* Uses RAC ToggleButtonGroup for accessible segmented control
|
|
460
|
+
*/
|
|
461
|
+
export function SegmentedControl({ value }: SegmentedControlProps): JSX.Element;
|
|
462
|
+
export interface SelectOption {
|
|
463
|
+
id: string;
|
|
464
|
+
label: string;
|
|
465
|
+
value: string | null;
|
|
466
|
+
isDisabled?: boolean;
|
|
467
|
+
}
|
|
468
|
+
interface CustomSelectProps extends Omit<SelectProps<SelectOption>, 'children'> {
|
|
469
|
+
label: string;
|
|
470
|
+
options: SelectOption[];
|
|
471
|
+
placeholder?: string;
|
|
472
|
+
}
|
|
473
|
+
/**
|
|
474
|
+
* Reusable Select component following RAC pattern
|
|
475
|
+
* Label is inside the Select wrapper for proper a11y
|
|
476
|
+
*/
|
|
477
|
+
export function Select({ label, options, placeholder, ...props }: CustomSelectProps): JSX.Element;
|
|
478
|
+
interface StatCardProps {
|
|
479
|
+
title: string;
|
|
480
|
+
value: ReactNode;
|
|
481
|
+
description?: string;
|
|
482
|
+
}
|
|
483
|
+
/**
|
|
484
|
+
* StatCard component for displaying dashboard statistics
|
|
485
|
+
*
|
|
486
|
+
* @example
|
|
487
|
+
* <StatCard
|
|
488
|
+
* title="Total Sources"
|
|
489
|
+
* value={42}
|
|
490
|
+
* description="Active scraping sources"
|
|
491
|
+
* />
|
|
492
|
+
*
|
|
493
|
+
* @example
|
|
494
|
+
* // With icon as value
|
|
495
|
+
* <StatCard
|
|
496
|
+
* title="System Status"
|
|
497
|
+
* value={<CheckmarkCircle />}
|
|
498
|
+
* description="All systems operational"
|
|
499
|
+
* />
|
|
500
|
+
*/
|
|
501
|
+
export function StatCard({ title, value, description }: StatCardProps): JSX.Element;
|
|
502
|
+
interface SwitchProps extends Omit<_SwitchProps1, 'children'> {
|
|
503
|
+
children?: React.ReactNode;
|
|
504
|
+
}
|
|
505
|
+
export const Switch: ({ children, ...props }: SwitchProps) => JSX.Element;
|
|
506
|
+
export function Tabs({ children, ...props }: TabsProps): JSX.Element;
|
|
507
|
+
export function TabList<T extends object>({ children, ...props }: TabListProps<T>): JSX.Element;
|
|
508
|
+
export function Tab({ children, ...props }: TabProps): JSX.Element;
|
|
509
|
+
export function TabPanel({ children, ...props }: TabPanelProps): JSX.Element;
|
|
510
|
+
interface TextAreaProps extends Omit<TextFieldProps, 'type'> {
|
|
511
|
+
}
|
|
512
|
+
export function TextArea({ label, error, placeholder, value, ...props }: TextAreaProps): JSX.Element;
|
|
513
|
+
type ColorScheme = 'light' | 'dark';
|
|
514
|
+
interface ThemeContextType {
|
|
515
|
+
colorScheme: ColorScheme;
|
|
516
|
+
toggleColorScheme: () => void;
|
|
517
|
+
}
|
|
518
|
+
export function ThemeProvider({ children }: {
|
|
519
|
+
children: ReactNode;
|
|
520
|
+
}): JSX.Element;
|
|
521
|
+
export function useTheme(): ThemeContextType;
|
|
522
|
+
/**
|
|
523
|
+
* Type definitions for FermMap
|
|
524
|
+
*
|
|
525
|
+
* Shared types used across the application
|
|
526
|
+
*/
|
|
527
|
+
export interface FilterState {
|
|
528
|
+
category: string | null;
|
|
529
|
+
country: string | null;
|
|
530
|
+
searchQuery: string;
|
|
531
|
+
}
|
|
532
|
+
export interface CategoryColors {
|
|
533
|
+
marker: string;
|
|
534
|
+
badge: BadgeVariant;
|
|
535
|
+
}
|
|
536
|
+
/**
|
|
537
|
+
* Type definitions for FermMap
|
|
538
|
+
*
|
|
539
|
+
* Shared types used across the application
|
|
540
|
+
*/
|
|
541
|
+
export interface Ferment {
|
|
542
|
+
id: number;
|
|
543
|
+
name: string;
|
|
544
|
+
slug: string;
|
|
545
|
+
description: string;
|
|
546
|
+
country: string;
|
|
547
|
+
countryCode: string;
|
|
548
|
+
region: string;
|
|
549
|
+
regionName?: string | null;
|
|
550
|
+
category: string;
|
|
551
|
+
ingredients: string[] | null;
|
|
552
|
+
imageUrl: string | null;
|
|
553
|
+
sourceUrl: string | null;
|
|
554
|
+
latitude: number | null;
|
|
555
|
+
longitude: number | null;
|
|
556
|
+
relatedFerments?: RelatedFerment[];
|
|
557
|
+
}
|
|
558
|
+
export interface RelatedFerment {
|
|
559
|
+
id: number;
|
|
560
|
+
name: string;
|
|
561
|
+
slug: string;
|
|
562
|
+
category?: string;
|
|
563
|
+
imageUrl?: string | null;
|
|
564
|
+
country: string;
|
|
565
|
+
countryCode?: string;
|
|
566
|
+
}
|
|
567
|
+
export interface Country {
|
|
568
|
+
code: string;
|
|
569
|
+
name: string;
|
|
570
|
+
region: string;
|
|
571
|
+
hasFerments: boolean;
|
|
572
|
+
}
|
|
573
|
+
export interface Category {
|
|
574
|
+
name: string;
|
|
575
|
+
category: string;
|
|
576
|
+
}
|
|
577
|
+
/**
|
|
578
|
+
* Filter context type with state and update methods
|
|
579
|
+
*/
|
|
580
|
+
interface FilterContextType {
|
|
581
|
+
filters: FilterState;
|
|
582
|
+
updateFilter: <K extends keyof FilterState>(key: K, value: FilterState[K]) => void;
|
|
583
|
+
clearFilters: () => void;
|
|
584
|
+
}
|
|
585
|
+
/**
|
|
586
|
+
* Filter Provider Component
|
|
587
|
+
* Manages filter state for the application
|
|
588
|
+
*
|
|
589
|
+
* @example
|
|
590
|
+
* <FilterProvider>
|
|
591
|
+
* <App />
|
|
592
|
+
* </FilterProvider>
|
|
593
|
+
*/
|
|
594
|
+
export function FilterProvider({ children }: {
|
|
595
|
+
children: ReactNode;
|
|
596
|
+
}): JSX.Element;
|
|
597
|
+
/**
|
|
598
|
+
* Hook to access filter context
|
|
599
|
+
* Must be used within FilterProvider
|
|
600
|
+
*
|
|
601
|
+
* @example
|
|
602
|
+
* const { filters, updateFilter, clearFilters } = useFilters();
|
|
603
|
+
* updateFilter('category', 'dairy');
|
|
604
|
+
*/
|
|
605
|
+
export function useFilters(): FilterContextType;
|
|
606
|
+
export function AxeDevTools(): null;
|
|
607
|
+
/**
|
|
608
|
+
* Default filter state
|
|
609
|
+
*/
|
|
610
|
+
export const DEFAULT_FILTERS: FilterState;
|
|
611
|
+
/**
|
|
612
|
+
* Check if any filters are active
|
|
613
|
+
*/
|
|
614
|
+
export function hasActiveFilters(filters: FilterState): boolean;
|
|
615
|
+
/**
|
|
616
|
+
* Clear all filters, returning default state
|
|
617
|
+
*/
|
|
618
|
+
export function clearFilters(): FilterState;
|
|
619
|
+
/**
|
|
620
|
+
* Update a single filter field
|
|
621
|
+
*/
|
|
622
|
+
export function updateFilter(filters: FilterState, field: keyof FilterState, value: string | null): FilterState;
|
|
623
|
+
/**
|
|
624
|
+
* Convert filter state to API query parameters
|
|
625
|
+
* Only includes non-empty filters
|
|
626
|
+
*/
|
|
627
|
+
export function filtersToQueryParams(filters: FilterState): Record<string, string>;
|
|
628
|
+
/**
|
|
629
|
+
* Get colors for a ferment category
|
|
630
|
+
* Returns marker color (for map), badge background, and badge text color
|
|
631
|
+
*
|
|
632
|
+
* @example
|
|
633
|
+
* const colors = getCategoryColors('dairy');
|
|
634
|
+
* // { marker: 'var(--plum-500)', badge: 'plum' }
|
|
635
|
+
*/
|
|
636
|
+
export function getCategoryColors(category: string): CategoryColors;
|
|
637
|
+
export interface FermentsResponse {
|
|
638
|
+
ferments: Ferment[];
|
|
639
|
+
count: number;
|
|
640
|
+
filters?: {
|
|
641
|
+
category?: string;
|
|
642
|
+
country?: string;
|
|
643
|
+
};
|
|
644
|
+
}
|
|
645
|
+
export interface FermentDetailResponse extends Ferment {
|
|
646
|
+
relatedFerments: Array<RelatedFerment>;
|
|
647
|
+
}
|
|
648
|
+
export interface SearchResponse {
|
|
649
|
+
results: Ferment[];
|
|
650
|
+
query: string;
|
|
651
|
+
count: number;
|
|
652
|
+
}
|
|
653
|
+
export interface FilterOptions {
|
|
654
|
+
category?: string;
|
|
655
|
+
country?: string;
|
|
656
|
+
limit?: number;
|
|
657
|
+
offset?: number;
|
|
658
|
+
}
|
|
659
|
+
/**
|
|
660
|
+
* API client object with all endpoint methods
|
|
661
|
+
*/
|
|
662
|
+
export const api: {
|
|
663
|
+
/**
|
|
664
|
+
* Get list of ferments with optional filters
|
|
665
|
+
*/
|
|
666
|
+
getFerments(filters?: FilterOptions): Promise<FermentsResponse>;
|
|
667
|
+
/**
|
|
668
|
+
* Get optimized data for map markers
|
|
669
|
+
*/
|
|
670
|
+
getFermentsForMap(): Promise<{
|
|
671
|
+
ferments: Array<Pick<Ferment, "id" | "name" | "latitude" | "longitude" | "category" | "country">>;
|
|
672
|
+
}>;
|
|
673
|
+
/**
|
|
674
|
+
* Search ferments by name or description
|
|
675
|
+
*/
|
|
676
|
+
searchFerments(query: string): Promise<SearchResponse>;
|
|
677
|
+
/**
|
|
678
|
+
* Get list of countries with hasFerments flag
|
|
679
|
+
* Optionally filtered by category
|
|
680
|
+
*/
|
|
681
|
+
getCountries(category?: string): Promise<{
|
|
682
|
+
countries: Country[];
|
|
683
|
+
}>;
|
|
684
|
+
/**
|
|
685
|
+
* Get list of categories
|
|
686
|
+
* Optionally filtered by country
|
|
687
|
+
*/
|
|
688
|
+
getCategories(country?: string): Promise<{
|
|
689
|
+
categories: Category[];
|
|
690
|
+
}>;
|
|
691
|
+
};
|
|
692
|
+
|
|
693
|
+
//# sourceMappingURL=types.d.ts.map
|