fermmap-shared 0.1.2 → 0.1.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.
@@ -1 +1 @@
1
- {"mappings":"ACQsB;EAAA;;;;EAAA;;;;EAUF;;;;EAAA;;;;EAAA;;;;EAiBE;;;;EAAA;;;;EAAA;;;;EAcI;;;;ECnCL;;;;;;EAAA;;;;EAAA;;;;EAAA;;;;;EAAA;;;;;EAAA;;;;EAAA;;;;;EAAA;;;;EAAA;;;;EC6CI;;;;EAsDE;;;;;EAeJ;;;;EAAA;;;;ECxHC;;;;EAAA;;;;EAOK;;;;ECkCT;;;;EA6BF;;;;;EAkBC;;;;;EAAA;;;;EAiBQ;;;;EAQF;;;;EAAA;;;;EAAA;;;;EAAA;;;;EAaG;;;;EAAA;;;;ECxHL;;;;EAiBL;;;;EAAA;;;;EAAA;;;;EAAA;;;;EAAA;;;;EAAA;;;;EAAA;;;;EAAA;;;;EAuCC;;;;EAAA;;;;ECpDC;;;;EAcY;;;;EAAA;;;;ECrBZ;;;;EAAA;;;;EAAA;;;;EAAA;;;;EAAA;;;;EAAA;;;;;;EAAA;;;;EAAA;;;;EAAA;;;;EAAA;;;;ECkCO;;;;EAAA;;;;ECtCK;;;;EAkBZ;;;;EAAA;;;;EA0BC;;;;EAAA;;;;EAoBC;;;;EA6CI;;;;EAKN;;;;ECvGc;;;;EAAA;;;;EAAA;;;;EAWF;;;;EAAA;;;;EAAA;;;;EAAA;;;;EAAA;;;;EAAA;;;;EA8BF;;;;EAAA;;;;EAAA;;;;EAAA;;;;EAAA;;;;EA+DE;;;;EAAA;;;;ECrGL;;;;ECFP;;;;EAAA;;;;EAAA;;;;EAaA;;;;EAqBM;;;;EAAA;;;;EAAA;;;;EAAA;;;;EAAA;;;;EAAA;;;;EAsBE;;;;EAAA;;;;EAAA;;;;EAAA;;;;EAWR;;;;EAAA;;;;EC1DM;;;;EAAA;;;;EAiBN;;;;EAeM;;;;EAAA;;;;EAAA;;;;EAAA;;;;EAAA;;;;EAAA;;;;ECpCC;;;;EAAA;;;;EAAA;;;;EAAA;;;;EAAA;;;;EAAA;;;;EAAA;;;;EAgCM;;;;EAAA;;;;EAAA;;;;EAAA;;;;EAAA;;;;EAAA;;;;EAAA;;;;EAAA;;;;EAAA;;;;EAAA;;;;EAAA;;;;EAAA;;;;EAAA;;;;;;EC7BZ;;;;EAAA;;;;EAAA;;;;EAAA;;;;EAAA;;;;;EAAA;;;;EAAA;;;;EAAA;;;;EA6BC;;;;EAAA;;;;EAAA;;;;EAAA;;;;EAAA;;;;EAAA;;;;EAAA;;;;EAaA;;;;EAAA;;;;EAKI;;;;EAAA;;;;EAAA;;;;EAAA;;;;EAAA;;;;EAAA;;;;EAAA;;;;EAAA;;;;EAAA;;;;EAAA;;;;EAAA;;;;EAAA;;;;EC/DP;;;;EAAA;;;;EAAA;;;;EAAA;;;;EAAA;;;;EAAA;;;;EAAA;;;;EAAA;;;;EAAA;;;;EAAA;;;;EAAA;;;;EAAA;;;;EAcK;;;;EAMA;;;;EAAA;;;;EAAA;;;;EAKD;;;;EAAA;;;;EAAA;;;;EAAA;;;;EC9BO;;;;EAAA;;;;EAAA;;;;EAAA;;;;EAiBJ;;;;EAAA;;;;EAAA;;;;EAAA;;;;EAAA;;;;EAAA;;;;EAAA;;;;EAAA;;;;EAAA;;;;EAAA;;;;EAuBA;;;;EAAA;;;;EAAA;;;;EAAA;;;;EAAA;;;;EAAA;;;;EAAA;;;;EAAA;;;;EAAA;;;;EC1CP;;;;EAAA;;;;EAAA;;;;EAMG;;;;EAAA;;;;EAAA;;;;EAAA;;;;EASJ;;;;EAAA;;;;EAAA;;;;EAAA;;;;EAAA;;;;EAAA;;;;EAAA;;;;EAAA;;;;EAAA;;;;EAAA;;;;EAAA;;;;EAAA;;;;EAAA;;;;EAAA;;;;EAAA;;;;EAAA;;;;EAAA;;;;EAAA;;;;EAAA;;;;EAAA;;;;EAAA;;;;EAAA;;;;EAAA;;;;EAmCK;;;;EAAA;;;;EAAA;;;;ECxCA;;;;EAAA;;;;EAAA;;;;EAAA;;;;EAAA;;;;EAAA;;;;EAAA;;;;EAAA;;;;EAAA;;;;EAAA;;;;EAAA;;;;EAAA;;;;EAAA;;;;EAAA;;;;EAAA;;;;EAAA;;;;EAAA;;;;EAAA;;;;EAAA;;;;EAAA;;;;EAAA;;;;EAAA;;;;EAAA;;;;EAAA;;;;EAAA;;;;EAAA;;;;EAAA;;;;EAAA;;;;EAAA;;;;EAAA;;;;;AnBIH;EYCA;;;;EAAA;;;;EAAA;;;;EIYI;;;;EAAA;;;;ECzBM;;;;ECaZ;;;;EAAA;;;;EAAA;;;;ECLK;;;;EAAA;;;;;AnBIH;EgBOI;;;;EAAA;;;;EAAA;;;;EAMA;;;;EAAA;;;;EAAA;;;;ECzBM;;;;ECaZ;;;;;AlBDE;EAAA;IAAA;;;;;;AAAA;EAAA;IAAA;;;;;;AAiBE;EgBVE;;;;EAAA;;;;EAAA;;;;EAMA;;;;EAAA;;;;EAAA;;;;EAKD;;;;;AhBDD;EgBJE;;;;EAAA;;;;EAAA;;;;EAKD;;;;;AhBDD;EgBJE;;;;EAAA;;;;EAAA;;;;EAKD;;;;;AhBDD;EAAA;;;;;AAAA;EAAA;;;;;AAAA;EAAA;;;;;ACrBD;EAAA;IAAA;;;;Ia0CY;;;;IAAA;;;;IGjCP;;;;IAAA;;;;IAAA;;;;IAAA;;;;IAAA;;;;IAAA;;;;IAuBA;;;;;;AG5C1B;;;;;;;;;;;AAWA;;;;;;AAMA;;;;AClBA;;;;AAIA;;;;AAIA;;;;;;;;;;ACHA;;;;AAIA;;;;AAIA;;;;;;;;;;;;AAYA;;;;;;;;;;;;AT+FwF;;AAAA;EAAA;IAAA","sources":["27d1e9fc0b161a21","packages/shared/src/components/AlertDialog.tsx","packages/shared/src/components/Button.tsx","packages/shared/src/components/Autocomplete.tsx","packages/shared/src/components/AutocompleteTable.tsx","packages/shared/src/components/Table.tsx","packages/shared/src/components/Checkbox.tsx","packages/shared/src/components/ProgressBar.tsx","packages/shared/src/components/Badge.tsx","packages/shared/src/components/CloseButton.tsx","packages/shared/src/components/ComboBox.tsx","packages/shared/src/components/DisclosureGroup.tsx","packages/shared/src/components/LabeledValue.tsx","packages/shared/src/components/RadioGroup.tsx","packages/shared/src/components/SearchField.tsx","packages/shared/src/components/SegmentedControl.tsx","packages/shared/src/components/Select.tsx","packages/shared/src/components/StatCard.tsx","packages/shared/src/components/Switch.tsx","packages/shared/src/components/Tabs.tsx","packages/shared/src/components/TextArea.tsx","packages/shared/src/components/Checkbox.css","packages/shared/src/components/ProgressBar.css","packages/shared/src/components/DisclosureGroup.css"],"sourcesContent":["@import \"9f47f68ba38c295a\";\n@import \"78c590a309b0e6a4\";\n@import \"290522a232eb340f\";\n@import \"9d168f2695c440b5\";\n@import \"cc4d3a5fac51363d\";\n@import \"8ee7d6e801b40a1c\";\n@import \"6ffa14505a299e4e\";\n@import \"cfef988437953ae9\";\n@import \"93c21ad3845ca137\";\n@import \"83429286ceb3be13\";\n@import \"03dd1cfb5962a09d\";\n@import \"620de91e79ad0a16\";\n@import \"d274ac5a14987bf9\";\n@import \"416838a95541a7c4\";\n@import \"53f941c4c340fa03\";\n@import \"82593e9a11ceb790\";\n@import \"4312b6d61177a486\";\n@import \"7f7804fa3c921faf\";\n@import \"29e82be3069c1c2c\";\n@import \"26b1a04880d0efb1\";\n@import \"f315d14c1596594f\";\n@import \"245a17a9caf6065d\";\n@import \"03b25ce5fcd826d5\";\n@import \"f64b1199c5ac10c2\";\n@import \"d00995e4bf421650\";\n@import \"418c33e40e8fa307\";\n@import \"77a381a4ad5e4deb\";\n@import \"79a47b3e11bde76b\";\n@import \"4c61b37e83b6cbaf\";\n@import \"7d6c90f6382f216d\";\n@import \"d5a82419c43c0258\";\n@import \"4c5c6d90d8125894\";\n@import \"d7830e0fdb5f5a4f\";\n@import \"3cb9bcfb6f0038f8\";\n@import \"8d4f769c29e4ee31\";\n@import \"e8338bb3ae3fb1c4\";\n@import \"541891615c093f21\";\n@import \"3415552572bd8d79\";\n@import \"30bf95091f7ade51\";\n@import \"f03216825356c24c\";\n@import \"a035a1ff61c82329\";\n@import \"f0b45c7a5a4ee6b4\";\n@import \"00d20b13f70db88f\";\n@import \"99348462226d32b0\";\n@import \"f133ffb8107f1499\";\n@import \"060090694d7abb5e\";\n@import \"02d1fda45f088142\";\n@import \"0be6be6f1b4df772\";\n@import \"d000b87b862d640a\";\n@import \"99cf12a0bc5155d4\";\n@import \"3dea62b5608bc4c7\";\n@import \"00dffe07cf30c480\";\n@import \"daa2dcfcc6aba2ec\";\n@import \"22d59f7061eee5c3\";\n@import \"c730c2c683575e83\";\n@import \"4c4abb4dd24ed78d\";\n@import \"55d42732ed05bd7c\";\n@import \"7e7d0afbf7be7aaf\";\n@import \"fe26295011b80084\";\n@import \"98f373d7d990b86e\";\n@import \"44556bb5ffa970fa\";\n@import \"ffb67edd6d59f4d0\";\n@import \"3f8a3d39101fb8de\";\n@import \"da5d3570a6be5108\";\n@import \"a81b95f6ba098d94\";\n@import \"6e45401afedcc213\";\n@import \"823e68b0820e33b0\";\n@import \"6098b6422a6b5107\";\n@import \"e704ae4b0ea5b6a4\";\n@import \"18ca83a63b402953\";\n@import \"9934fabeca5dc14b\";\n@import \"08e05744d70ceb2e\";\n@import \"51f566c4383bc873\";\n@import \"00f37031e59ae452\";\n@import \"b2e8234656a0acab\";\n@import \"1c127e7148e69ee6\";\n@import \"31b2213af713491b\";\n@import \"c313bd17239b6dfb\";\n@import \"cc3cacc59937fd97\";\n@import \"1b5034e53b6b6e9d\";\n@import \"f43b41886b283acc\";\n@import \"b30e558e03268eb5\";\n@import \"16fa3c2822ce8fa6\";\n@import \"6cc8a6d86b48a0f8\";\n@import \"2d5249b468c9ed81\";\n@import \"d69789ae2771f37d\";\n@import \"a750f611c47db198\";\n@import \"2243763201ee6943\";\n@import \"2c30d3e83234d14f\";\n@import \"e9c2f06a78f0fa1b\";\n@import \"1629b57b41de7f33\";\n@import \"d38717759287a5cb\";\n@import \"5046bf9ea1029bc4\";\n@import \"a33499d27b9fcd76\";\n@import \"a31990ea1642f273\";\n@import \"d1b031cf4bda7480\";\n@import \"e81d7eb3988d206b\";\n@import \"6f65c616b892c898\";\n@import \"adda47912e5baae7\";\n@import \"d9ef614c1a51f3a0\";\n@import \"36dbb656eeb11098\";\n@import \"d3b3b5097317263d\";\n@import \"c7bfffb20d48ffa6\";\n@import \"75d222754bbb0b8f\";\n@import \"b79287f289978582\";\n@import \"55cf679aaecacd02\";\n@import \"a4a1c07b3ebdf826\";\n@import \"5a19908ab4aad173\";\n","'use client';\n\nimport { Button } from './Button';\nimport { Dialog, Heading, Modal, ModalOverlay } from 'react-aria-components';\nimport { style } from '@react-spectrum/s2/style' with { type: 'macro' };\nimport { TextField } from './TextField';\nimport { useState } from 'react';\n\nconst overlayStyles = style({\n position: 'fixed',\n inset: 0,\n backgroundColor: 'transparent-black-500',\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n isolation: 'isolate',\n});\n\nconst modalStyles = style({\n backgroundColor: 'layer-1',\n borderRadius: 'xl',\n boxShadow: 'elevated',\n padding: 24,\n width: {\n default: 'calc(100vw - 32px)',\n sm: 400,\n md: 500\n },\n maxWidth: 500,\n transform: {\n entering: 'scale(0.95)',\n default: 'scale(1)'\n },\n});\n\nconst headingStyles = style({\n font: 'heading-xl',\n color: 'heading',\n margin: 0,\n marginBottom: 12\n});\n\nconst messageStyles = style({\n font: 'body',\n color: 'neutral',\n margin: 0,\n marginBottom: 24\n});\n\nconst buttonGroupStyles = style({\n display: 'flex',\n gap: 12,\n justifyContent: 'end'\n});\n\nexport interface AlertDialogProps {\n isOpen: boolean;\n onClose: () => void;\n title: string;\n message: string;\n variant?: 'danger' | 'warning' | 'info' | 'success';\n confirmLabel?: string;\n cancelLabel?: string;\n onConfirm: () => void | Promise<void>;\n showCancel?: boolean;\n children?: React.ReactNode; // Optional custom content (e.g., Switch, Checkbox)\n}\n\nexport function AlertDialog({\n isOpen,\n onClose,\n title,\n message,\n variant = 'info',\n confirmLabel = 'OK',\n cancelLabel = 'Cancel',\n onConfirm,\n showCancel = true,\n children\n}: AlertDialogProps) {\n const [isProcessing, setIsProcessing] = useState(false);\n\n const handleConfirm = async () => {\n setIsProcessing(true);\n try {\n await onConfirm();\n onClose();\n } finally {\n setIsProcessing(false);\n }\n };\n\n // Map variant to button variant\n const buttonVariant = variant === 'danger' ? 'danger' :\n variant === 'success' ? 'primary' :\n 'primary';\n\n return (\n <ModalOverlay isOpen={isOpen} onOpenChange={(open) => !open && onClose()} className={overlayStyles}>\n <Modal className={modalStyles}>\n <Dialog>\n {({ close }) => (\n <>\n <Heading slot=\"title\" className={headingStyles}>\n {title}\n </Heading>\n <p className={messageStyles}>{message}</p>\n {children && (\n <div className={style({ marginBottom: 24 })}>\n {children}\n </div>\n )}\n <div className={buttonGroupStyles}>\n {showCancel && (\n <Button\n variant=\"secondary\"\n size=\"M\"\n onPress={close}\n isDisabled={isProcessing}\n >\n {cancelLabel}\n </Button>\n )}\n <Button\n variant={buttonVariant}\n size=\"M\"\n onPress={handleConfirm}\n isDisabled={isProcessing}\n >\n {isProcessing ? 'Processing...' : confirmLabel}\n </Button>\n </div>\n </>\n )}\n </Dialog>\n </Modal>\n </ModalOverlay>\n );\n}\n\nexport interface PromptDialogProps {\n isOpen: boolean;\n onClose: () => void;\n title: string;\n message: string;\n inputLabel: string;\n inputPlaceholder?: string;\n confirmLabel?: string;\n cancelLabel?: string;\n onConfirm: (value: string) => void | Promise<void>;\n validator?: (value: string) => string | null;\n}\n\nexport function PromptDialog({\n isOpen,\n onClose,\n title,\n message,\n inputLabel,\n inputPlaceholder = '',\n confirmLabel = 'OK',\n cancelLabel = 'Cancel',\n onConfirm,\n validator\n}: PromptDialogProps) {\n const [value, setValue] = useState('');\n const [error, setError] = useState<string | null>(null);\n const [isProcessing, setIsProcessing] = useState(false);\n\n const handleConfirm = async () => {\n // Validate\n if (validator) {\n const validationError = validator(value);\n if (validationError) {\n setError(validationError);\n return;\n }\n }\n\n setIsProcessing(true);\n try {\n await onConfirm(value);\n setValue('');\n setError(null);\n onClose();\n } finally {\n setIsProcessing(false);\n }\n };\n\n const handleClose = () => {\n setValue('');\n setError(null);\n onClose();\n };\n\n return (\n <ModalOverlay isOpen={isOpen} onOpenChange={(open) => !open && handleClose()} className={overlayStyles}>\n <Modal className={modalStyles}>\n <Dialog>\n {({ close }) => (\n <>\n <Heading slot=\"title\" className={headingStyles}>\n {title}\n </Heading>\n <p className={messageStyles}>{message}</p>\n <div className={style({ marginBottom: 24 })}>\n <TextField\n label={inputLabel}\n value={value}\n onChange={(newValue) => {\n setValue(newValue);\n setError(null);\n }}\n placeholder={inputPlaceholder}\n error={error || undefined}\n autoFocus\n />\n </div>\n <div className={buttonGroupStyles}>\n <Button\n variant=\"secondary\"\n size=\"M\"\n onPress={() => {\n setValue('');\n setError(null);\n close();\n }}\n isDisabled={isProcessing}\n >\n {cancelLabel}\n </Button>\n <Button\n variant=\"primary\"\n size=\"M\"\n onPress={handleConfirm}\n isDisabled={isProcessing}\n >\n {isProcessing ? 'Processing...' : confirmLabel}\n </Button>\n </div>\n </>\n )}\n </Dialog>\n </Modal>\n </ModalOverlay>\n );\n}\n","import { Button as AriaButton, ButtonProps as AriaButtonProps } from 'react-aria-components';\nimport { focusRing, style } from '@react-spectrum/s2/style' with { type: 'macro' };\n\n// For props: https://react-spectrum.adobe.com/react-aria/Button.html#props\n// For styling: https://react-spectrum.adobe.com/react-aria/Button.html#styling\n// For conditional styling: https://react-spectrum.adobe.com/beta/s2/styling.html#conditional-styles\n\nexport interface ButtonProps extends AriaButtonProps {\n children?: React.ReactNode;\n variant?: 'primary' | 'secondary' | 'danger' | 'navigation';\n size?: 'S' | 'M' | 'L';\n}\n\n// Primary variant styles\nconst buttonStyles = style({\n ...focusRing(),\n font: {\n default: 'body',\n size: {\n S: 'body-sm',\n L: 'body-lg',// or `body` too?\n },\n },\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n gap: {\n default: 8,\n size: {\n S: 4,\n },\n },\n paddingY: {\n default: 12,\n size: {\n S: 8,\n L: 16,\n },\n variant: {\n navigation: {\n default: 4\n }\n }\n },\n paddingStart: {\n default: 16,\n size: {\n S: 12,\n L: 24,\n },\n variant: {\n navigation: {\n default: 8\n }\n }\n },\n paddingEnd: {\n default: 16,\n size: {\n S: 12,\n L: 24,\n },\n variant: {\n navigation: 12\n }\n },\n width: {\n variant: {\n navigation: 'fit'\n }\n },\n color: {\n variant: {\n secondary: {\n default: '--plum-700',\n },\n danger: {\n default: 'white',\n },\n navigation: {\n default: '--plum-700',\n }\n },\n forcedColors: 'ButtonText',\n isDisabled: {\n default: 'gray-400',\n forcedColors: 'GrayText',\n },\n },\n backgroundColor: {\n default: '--plum-300',\n variant: {\n primary: {\n default: '--plum-300',\n isHovered: '--plum-400',\n isFocusVisibile: '--plum-400',\n isPressed: '--plum-400',\n },\n secondary: {\n default: '--yogurt-200',\n isHovered: '--yogurt-300',\n isFocusVisibile: '--yogurt-300',\n isPressed: '--yogurt-400',\n },\n navigation: {\n default: 'transparent',\n isHovered: '--yogurt-200',\n isFocusVisibile: '--yogurt-200',\n isPressed: '--yogurt-300',\n },\n danger: {\n default: '--berry-500',\n isHovered: '--berry-600',\n isFocusVisibile: '--berry-600',\n isPressed: '--berry-700',\n },\n },\n forcedColors: 'ButtonFace',\n isDisabled: {\n default: 'gray-100',\n isDisabled: 'GrayText',\n },\n },\n borderRadius: 'lg',\n borderStyle: {\n default: 'none',\n forcedColors: 'solid'\n },\n borderColor: {\n forcedColors: 'ButtonBorder'\n },\n borderWidth: {\n forcedColors: 1\n },\n cursor: {\n default: 'pointer',\n isDisabled: 'not-allowed'\n }\n});\n\nexport const Button = ({\n children,\n variant = 'primary',\n size = 'M',\n className,\n ...props\n}: ButtonProps) => {\n return (\n <AriaButton\n {...props}\n className={renderProps => `${className || ''} ` + buttonStyles({ ...renderProps, size, variant })}\n >\n {children}\n </AriaButton>\n );\n};\n","'use client';\n\nimport { useState, useMemo } from 'react';\nimport {\n SearchField as AriaSearchField,\n Autocomplete as AriaAutocomplete,\n Input,\n Label,\n ListBox,\n ListBoxItem,\n useFilter,\n Popover\n} from 'react-aria-components';\nimport { focusRing, style } from '@react-spectrum/s2/style' with { type: 'macro' };\nimport Search from '@react-spectrum/s2/icons/Search';\nimport CheckmarkCircle from '@react-spectrum/s2/icons/CheckmarkCircle';\nimport type { Selection } from 'react-aria-components';\n\nconst containerStyles = style({\n display: 'flex',\n flexDirection: 'column',\n gap: 4,\n width: 'full',\n});\n\nconst labelStyles = style({\n font: 'body',\n color: '--plum-700',\n});\n\nconst searchFieldStyles = style({\n display: 'flex',\n flexDirection: 'column',\n gap: 4,\n});\n\nconst inputContainerStyles = style({\n position: 'relative',\n display: 'flex',\n alignItems: 'center',\n});\n\nconst inputStyles = style({\n ...focusRing(),\n width: 'full',\n padding: 8,\n paddingStart: 40,\n font: 'body',\n borderRadius: 'lg',\n borderWidth: 1,\n borderStyle: 'solid',\n borderColor: '--yogurt-400',\n backgroundColor: {\n default: '--yogurt-100',\n isHovered: '--yogurt-200',\n isFocusVisible: '--yogurt-200',\n },\n});\n\nconst searchIconStyles = style({\n position: 'absolute',\n left: 12,\n top: '50%',\n transform: 'translateY(-50%)',\n pointerEvents: 'none',\n color: '--yogurt-600',\n});\n\nconst popoverStyles = style({\n backgroundColor: '--yogurt-50',\n borderRadius: 'lg',\n borderWidth: 1,\n borderStyle: 'solid',\n borderColor: '--yogurt-400',\n boxShadow: 'elevated',\n marginTop: 4,\n maxHeight: 300,\n overflow: 'auto',\n isolation: 'isolate',\n // width: 'full',\n // minWidth: 300,\n});\n\nconst listBoxStyles = style({\n padding: 4,\n outline: 'none',\n});\n\nconst listBoxItemStyles = style({\n ...focusRing(),\n font: 'body',\n paddingX: 8,\n paddingY: 8,\n borderRadius: 'sm',\n cursor: 'pointer',\n display: 'flex',\n alignItems: 'center',\n gap: 8,\n backgroundColor: {\n default: 'transparent',\n isHovered: '--yogurt-200',\n isFocused: '--yogurt-200',\n isPressed: '--yogurt-300',\n },\n color: {\n default: '--plum-700',\n isHovered: '--plum-800',\n isFocused: '--plum-800',\n isPressed: '--plum-900',\n },\n outline: 'none',\n});\n\nconst selectedItemStyles = style({\n backgroundColor: {\n default: '--plum-100',\n isHovered: '--plum-200',\n isFocused: '--plum-200',\n },\n color: '--plum-900',\n});\n\nconst checkboxStyles = style({\n width: 16,\n height: 16,\n flexShrink: 0,\n});\n\nconst itemTextStyles = style({\n flex: 1,\n overflow: 'hidden',\n textOverflow: 'ellipsis',\n whiteSpace: 'nowrap',\n});\n\nconst errorStyles = style({\n font: 'body-sm',\n color: '--berry-600',\n});\n\nexport interface AutocompleteItem {\n id: string | number;\n name: string;\n [key: string]: any;\n}\n\nexport interface AutocompleteProps<T extends AutocompleteItem> {\n items: T[];\n selectedKeys?: Selection;\n onSelectionChange?: (keys: Selection) => void;\n selectionMode?: 'none' | 'single' | 'multiple';\n label: string;\n placeholder?: string;\n ariaLabel?: string;\n error?: string;\n getItemText?: (item: T) => string;\n}\n\n/**\n * Autocomplete component using React Aria SearchField + ListBox\n * \n * Features:\n * - SearchField for filtering items\n * - Optional checkboxes for multi-selection\n * - Shows both selected and unselected items when filtered\n * - Selected items highlighted with background color\n * - Keyboard navigation (arrow keys, enter, escape)\n * - Accessible (ARIA labels, focus management)\n * \n * @example\n * ```tsx\n * // Single select\n * <Autocomplete\n * items={sources}\n * selectedKeys={selectedKey}\n * onSelectionChange={setSelectedKey}\n * selectionMode=\"single\"\n * label=\"Select Source\"\n * placeholder=\"Search sources...\"\n * />\n * \n * // Multi select\n * <Autocomplete\n * items={sources}\n * selectedKeys={selectedKeys}\n * onSelectionChange={setSelectedKeys}\n * selectionMode=\"multiple\"\n * label=\"Select Sources\"\n * placeholder=\"Search sources...\"\n * />\n * \n * // No selection (just filtering)\n * <Autocomplete\n * items={sources}\n * selectionMode=\"none\"\n * label=\"Search Sources\"\n * placeholder=\"Search sources...\"\n * />\n * ```\n */\nexport function Autocomplete<T extends AutocompleteItem>({\n items,\n selectedKeys,\n onSelectionChange,\n selectionMode = 'none',\n label,\n placeholder,\n ariaLabel,\n error,\n getItemText = (item) => item.name,\n}: AutocompleteProps<T>) {\n const [inputValue, setInputValue] = useState('');\n const { contains } = useFilter({ sensitivity: 'base' });\n\n // Filter items based on input value\n const filteredItems = useMemo(() => {\n if (!inputValue) return items;\n const searchLower = inputValue.toLowerCase();\n return items.filter((item) =>\n getItemText(item).toLowerCase().includes(searchLower)\n );\n }, [items, inputValue, getItemText]);\n\n // Sort to show selected items first when in selection mode\n const sortedItems = useMemo(() => {\n if (selectionMode === 'none' || !selectedKeys) return filteredItems;\n\n return [...filteredItems].sort((a, b) => {\n const aSelected = selectedKeys === 'all' || selectedKeys.has(String(a.id));\n const bSelected = selectedKeys === 'all' || selectedKeys.has(String(b.id));\n if (aSelected && !bSelected) return -1;\n if (!aSelected && bSelected) return 1;\n return 0;\n });\n }, [filteredItems, selectedKeys, selectionMode]);\n\n const showCheckboxes = selectionMode !== 'none';\n\n return (\n <div className={containerStyles}>\n <AriaAutocomplete\n filter={contains}\n inputValue={inputValue}\n onInputChange={setInputValue}\n >\n <AriaSearchField\n className={searchFieldStyles}\n aria-label={ariaLabel || label}\n >\n <Label className={labelStyles}>{label}</Label>\n <div className={inputContainerStyles}>\n <div className={searchIconStyles}><Search /></div>\n <Input\n className={inputStyles}\n placeholder={placeholder}\n />\n </div>\n </AriaSearchField>\n\n <ListBox\n className={listBoxStyles}\n items={sortedItems}\n selectionMode={selectionMode}\n selectedKeys={selectedKeys}\n onSelectionChange={onSelectionChange}\n aria-label={ariaLabel || `${label} options`}\n >\n {(item) => {\n const isSelected = selectedKeys === 'all' || (selectedKeys && selectedKeys.has(String(item.id)));\n return (\n <ListBoxItem\n key={item.id}\n id={String(item.id)}\n textValue={getItemText(item)}\n className={(renderProps) =>\n `${listBoxItemStyles(renderProps)} ${isSelected ? selectedItemStyles(renderProps) : ''}`\n }\n >\n {showCheckboxes && (\n <div className={checkboxStyles}>\n {isSelected && <CheckmarkCircle />}\n </div>\n )}\n <span className={itemTextStyles}>{getItemText(item)}</span>\n </ListBoxItem>\n );\n }}\n </ListBox>\n\n {error && <div className={errorStyles}>{error}</div>}\n </AriaAutocomplete>\n </div>\n );\n}\n","'use client';\n\nimport { useMemo } from 'react';\nimport type { Selection } from 'react-aria-components';\nimport { Autocomplete, type AutocompleteItem } from './Autocomplete';\nimport { Table, type ColumnDef } from './Table';\nimport { style } from '@react-spectrum/s2/style' with { type: 'macro' };\n\nconst containerStyles = style({\n display: 'flex',\n flexDirection: 'column',\n gap: 16,\n width: 'full',\n});\n\nconst tableContainerStyles = style({\n maxHeight: 384,\n overflow: 'auto',\n});\n\nexport interface AutocompleteTableProps<T extends AutocompleteItem> {\n // Autocomplete props\n allItems: T[];\n selectedKeys: Selection;\n onSelectionChange: (keys: Selection) => void;\n selectionMode?: 'single' | 'multiple';\n searchLabel: string;\n searchPlaceholder?: string;\n getItemText?: (item: T) => string;\n\n // Table props\n columns: ColumnDef<T>[];\n tableLabel: string;\n}\n\n/**\n * Composite component combining Autocomplete and Table\n * Useful for search-and-select workflows where selected items are displayed in a table\n * \n * Features:\n * - Autocomplete search field at top\n * - Table below showing selected items\n * - Filters all items in autocomplete\n * - Shows only selected items in table\n * - Scrollable table with max height of 384px\n * \n * @example\n * ```tsx\n * <AutocompleteTable\n * allItems={allSources}\n * selectedKeys={selectedSourceIds}\n * onSelectionChange={setSelectedSourceIds}\n * selectionMode=\"multiple\"\n * searchLabel=\"Search Sources\"\n * searchPlaceholder=\"Search by name or URL...\"\n * columns={[\n * { key: 'name', label: 'Name', isRowHeader: true },\n * { key: 'domain', label: 'Domain' },\n * { key: 'actions', label: 'Actions', align: 'end' },\n * ]}\n * tableLabel=\"Selected Sources\"\n * />\n * ```\n */\nexport function AutocompleteTable<T extends AutocompleteItem>({\n allItems,\n selectedKeys,\n onSelectionChange,\n selectionMode = 'multiple',\n searchLabel,\n searchPlaceholder,\n getItemText,\n columns,\n tableLabel,\n}: AutocompleteTableProps<T>) {\n // Filter to show only selected items in table\n const selectedItems = useMemo(() => {\n if (selectedKeys === 'all') return allItems;\n if (!selectedKeys || selectedKeys.size === 0) return [];\n\n return allItems.filter(item => selectedKeys.has(String(item.id)));\n }, [allItems, selectedKeys]);\n\n return (\n <div className={containerStyles}>\n <Autocomplete\n items={allItems}\n selectedKeys={selectedKeys}\n onSelectionChange={onSelectionChange}\n selectionMode={selectionMode}\n label={searchLabel}\n placeholder={searchPlaceholder}\n getItemText={getItemText}\n />\n\n <div className={tableContainerStyles}>\n <Table\n columns={columns}\n data={selectedItems}\n ariaLabel={tableLabel}\n />\n </div>\n </div>\n );\n}\n","'use client';\n\nimport {\n Cell,\n Column,\n Row,\n Table as AriaTable,\n TableBody,\n TableHeader,\n type Key,\n type SortDescriptor\n} from 'react-aria-components';\nimport { focusRing, style } from '@react-spectrum/s2/style' with { type: 'macro' };\nimport { Checkbox } from './Checkbox';\nimport { ProgressBar } from './ProgressBar';\nimport { ReactNode, useRef, useEffect } from 'react';\n\nexport interface ColumnDef<T> {\n key: string;\n label: string;\n renderCell: (item: T) => ReactNode;\n width?: string;\n isRowHeader?: boolean;\n align?: 'start' | 'center' | 'end';\n}\n\nexport interface TableProps<T> {\n data: T[];\n columns: ColumnDef<T>[];\n onRowAction?: (key: Key) => void;\n ariaLabel: string;\n sortDescriptor?: SortDescriptor;\n onSortChange?: (descriptor: SortDescriptor) => void;\n selectionMode?: 'none' | 'single' | 'multiple';\n selectedKeys?: Set<Key>;\n onSelectionChange?: (keys: Set<Key>) => void;\n onLoadMore?: () => void;\n isLoadingMore?: boolean;\n}\n\nconst tableContainerStyles = style({\n backgroundColor: 'layer-1',\n borderRadius: 'xl',\n borderWidth: 1,\n borderStyle: 'solid',\n borderColor: '--plum-200',\n overflow: 'hidden'\n});\n\nconst tableStyles = style({\n width: 'full',\n borderCollapse: 'collapse'\n});\n\nconst tableHeaderStyles = style({\n backgroundColor: '--yogurt-200',\n borderBottomWidth: 1,\n borderBottomStyle: 'solid',\n borderBottomColor: '--plum-200'\n});\n\nconst columnHeaderStyles = style({\n padding: 16,\n textAlign: {\n default: 'start',\n align: {\n start: 'start',\n center: 'center',\n end: 'end',\n },\n },\n font: 'title-lg',\n color: '--plum-700',\n cursor: {\n allowsSorting: 'pointer'\n }\n});\n\nconst rowStyles = style({\n ...focusRing(),\n backgroundColor: {\n default: 'transparent',\n isHovered: '--yogurt-100',\n isSelected: '--plum-100',\n isFocusVisible: '--yogurt-100'\n },\n cursor: {\n default: 'default',\n onRowAction: 'pointer',\n selectionMode: {\n single: 'pointer',\n multiple: 'pointer'\n }\n }\n});\n\nconst cellStyles = style({\n padding: 16,\n textAlign: {\n default: 'start',\n align: {\n start: 'start',\n center: 'center',\n end: 'end',\n },\n },\n font: 'body',\n color: '--plum-700',\n borderBottomWidth: 1,\n borderBottomStyle: 'solid',\n borderBottomColor: '--plum-100'\n});\n\nconst checkboxCellStyles = style({\n padding: 16,\n width: 48,\n borderBottomWidth: 1,\n borderBottomStyle: 'solid',\n borderBottomColor: '--plum-100'\n});\n\nconst emptyStateStyles = style({\n padding: 48,\n textAlign: 'center',\n font: 'body',\n color: '--plum-600',\n});\n\nconst loadingStyles = style({\n padding: 24,\n display: 'flex',\n justifyContent: 'center'\n});\n\nconst scrollTriggerStyles = style({\n height: 1,\n pointerEvents: 'none'\n});\n\n/**\n * Reusable Table component using React Aria Components\n * \n * Features:\n * - Collection-based API for better performance\n * - Built-in virtualization support (via RAC)\n * - Keyboard navigation\n * - Screen reader support\n * - Optional sorting\n * - Optional row selection\n * - Optional row actions (clickable rows)\n * - Checkbox column for multiple selection\n * - Hover and selected states\n * \n * @example\n * ```tsx\n * const columns: ColumnDef<Run>[] = [\n * { key: 'id', label: 'ID', renderCell: (run) => `#${run.id}` },\n * { key: 'status', label: 'Status', renderCell: (run) => <Badge variant={run.status}>{run.status}</Badge> }\n * ];\n * \n * <Table\n * data={runs}\n * columns={columns}\n * ariaLabel=\"Scraper runs\"\n * selectionMode=\"multiple\"\n * selectedKeys={selectedIds}\n * onSelectionChange={setSelectedIds}\n * />\n * ```\n */\nexport function Table<T extends { id: number | string }>({\n data,\n columns,\n onRowAction,\n ariaLabel,\n sortDescriptor,\n onSortChange,\n selectionMode = 'none',\n selectedKeys,\n onSelectionChange,\n onLoadMore,\n isLoadingMore\n}: TableProps<T>) {\n const observerTarget = useRef<HTMLDivElement>(null);\n\n // Infinite scroll observer\n useEffect(() => {\n if (!onLoadMore) return;\n\n const observer = new IntersectionObserver(\n (entries) => {\n if (entries[0].isIntersecting && !isLoadingMore) {\n onLoadMore();\n }\n },\n { threshold: 0.1, rootMargin: '100px' }\n );\n\n if (observerTarget.current) {\n observer.observe(observerTarget.current);\n }\n\n return () => observer.disconnect();\n }, [onLoadMore, isLoadingMore]);\n\n return (\n <>\n <div className={tableContainerStyles}>\n <AriaTable\n aria-label={ariaLabel}\n selectionMode={selectionMode}\n selectedKeys={selectedKeys}\n onSelectionChange={onSelectionChange as any}\n onRowAction={onRowAction}\n sortDescriptor={sortDescriptor}\n onSortChange={onSortChange}\n className={tableStyles}\n >\n <TableHeader className={tableHeaderStyles}>\n {selectionMode === 'multiple' && (\n <Column className={columnHeaderStyles({ align: 'center', alignItems: 'center' })}>\n <Checkbox slot=\"selection\" size=\"S\" />\n </Column>\n )}\n {columns.map((column) => (\n <Column\n key={column.key}\n id={column.key}\n isRowHeader={column.isRowHeader}\n allowsSorting={!!onSortChange}\n className={columnHeaderStyles({ align: column.align })}\n >\n {column.label}\n </Column>\n ))}\n </TableHeader>\n <TableBody\n items={data}\n renderEmptyState={() => (\n <div className={emptyStateStyles}>\n No data available\n </div>\n )}\n >\n {(item) => (\n <Row\n key={item.id}\n id={item.id}\n className={(renderProps) => rowStyles({\n ...renderProps,\n onRowAction: !!onRowAction,\n selectionMode\n })}\n >\n {selectionMode === 'multiple' && (\n <Cell className={checkboxCellStyles}>\n <Checkbox slot=\"selection\" size=\"S\" />\n </Cell>\n )}\n {columns.map((column) => (\n <Cell key={column.key} className={cellStyles({ align: column.align })}>\n {column.renderCell(item)}\n </Cell>\n ))}\n </Row>\n )}\n </TableBody>\n </AriaTable>\n </div>\n\n {/* Infinite scroll trigger */}\n {onLoadMore && <div ref={observerTarget} className={scrollTriggerStyles} />}\n\n {/* Loading indicator */}\n {isLoadingMore && (\n <div className={loadingStyles}>\n <ProgressBar isIndeterminate aria-label=\"Loading more items\" />\n </div>\n )}\n </>\n );\n}\n\n","'use client';\n\nimport { Checkbox as AriaCheckbox, type CheckboxProps as AriaCheckboxProps } from 'react-aria-components';\nimport { focusRing, style } from '@react-spectrum/s2/style' with { type: 'macro' };\nimport './Checkbox.css';\n\nexport interface CheckboxProps extends Omit<AriaCheckboxProps, 'className' | 'style'> {\n /**\n * The size of the Checkbox.\n * @default 'M'\n */\n size?: 'S' | 'M' | 'L';\n}\n\nconst checkboxStyles = style({\n display: 'flex',\n position: 'relative',\n alignItems: 'center',\n gap: 8,\n font: 'body',\n color: {\n default: '--plum-700',\n isDisabled: 'disabled'\n },\n cursor: {\n default: 'pointer',\n isDisabled: 'default'\n },\n disableTapHighlight: true\n});\n\nconst boxStyles = style({\n ...focusRing(),\n size: {\n default: 20,\n size: {\n S: 16,\n M: 20,\n L: 24\n }\n },\n flexShrink: 0,\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n borderWidth: 2,\n borderStyle: 'solid',\n borderRadius: 'sm',\n transition: 'default',\n backgroundColor: {\n default: 'layer-1',\n isSelected: {\n default: '--plum-600',\n isHovered: '--plum-700',\n isPressed: '--plum-800'\n },\n isDisabled: {\n default: 'gray-100',\n isSelected: 'gray-400'\n }\n },\n borderColor: {\n default: '--plum-400',\n isHovered: '--plum-500',\n isPressed: '--plum-600',\n isSelected: 'transparent',\n isDisabled: 'gray-300'\n }\n});\n\nconst dashStyles = style({\n width: '60%',\n height: 2,\n backgroundColor: 'white',\n borderRadius: 'sm'\n});\n\n/**\n * Checkbox component for selection within tables and forms.\n * Simplified version based on React Spectrum S2 Checkbox.\n * \n * @example\n * ```tsx\n * <Checkbox isSelected={selected} onChange={setSelected}>\n * Subscribe to newsletter\n * </Checkbox>\n * \n * // In table header/cell (no label)\n * <Checkbox slot=\"selection\" />\n * ```\n */\nexport function Checkbox({ size = 'M', children, ...props }: CheckboxProps) {\n return (\n <AriaCheckbox\n {...props}\n className={(renderProps) => checkboxStyles(renderProps)}\n >\n {(renderProps) => {\n const { isSelected, isIndeterminate } = renderProps;\n\n return (\n <>\n <div className={boxStyles({ ...renderProps, isSelected: isSelected || isIndeterminate, size })}>\n {isIndeterminate ? (\n <div className={dashStyles} />\n ) : isSelected ? (\n <svg viewBox=\"0 0 18 18\" aria-hidden=\"true\" className=\"checkbox-checkmark\">\n <polyline points=\"2 9 7 14 16 4\" className=\"checkbox-checkmark-path checkbox-checkmark-selected\" />\n </svg>\n ) : null}\n </div>\n {children}\n </>\n );\n }}\n </AriaCheckbox>\n );\n}\n","import { ProgressBar as AriaProgressBar } from 'react-aria-components';\nimport { style } from '@react-spectrum/s2/style' with { type: 'macro' };\nimport './ProgressBar.css';\n\nconst progressBarStyles = style({\n display: 'flex',\n flexDirection: 'column',\n gap: 4,\n width: 'full',\n});\n\nconst labelStyles = style({\n font: 'body',\n color: '--plum-700',\n display: 'flex',\n justifyContent: 'space-between',\n});\n\nconst trackStyles = style({\n height: 6,\n backgroundColor: '--yogurt-200',\n borderRadius: 'full',\n overflow: 'hidden',\n position: 'relative',\n});\n\nconst fillStyles = style({\n height: 'full',\n backgroundColor: '--plum-500',\n borderRadius: 'full',\n});\n\nconst indeterminateFillStyles = style({\n height: 'full',\n backgroundColor: '--plum-500',\n borderRadius: 'full',\n width: '40%',\n});\n\ninterface ProgressBarProps {\n label?: string;\n value?: number;\n maxValue?: number;\n isIndeterminate?: boolean;\n showValueLabel?: boolean;\n 'aria-label'?: string;\n}\n\n/**\n * ProgressBar Component\n * \n * Accessible progress indicator using React Aria Components.\n * Supports both determinate (with value) and indeterminate (loading) states.\n * \n * @example\n * // Determinate progress\n * <ProgressBar label=\"Loading...\" value={50} maxValue={100} />\n * \n * @example\n * // Indeterminate progress\n * <ProgressBar label=\"Loading...\" isIndeterminate />\n */\nexport function ProgressBar({\n label,\n value = 0,\n maxValue = 100,\n isIndeterminate = false,\n showValueLabel = true,\n 'aria-label': ariaLabel,\n}: ProgressBarProps) {\n return (\n <AriaProgressBar\n value={isIndeterminate ? undefined : value}\n maxValue={maxValue}\n isIndeterminate={isIndeterminate}\n aria-label={ariaLabel || label}\n className={progressBarStyles}\n >\n {({ percentage, valueText }) => (\n <>\n {label && (\n <div className={labelStyles}>\n <span>{label}</span>\n {!isIndeterminate && showValueLabel && <span>{valueText}</span>}\n </div>\n )}\n <div className={trackStyles}>\n <div\n className={`${isIndeterminate ? 'progress-fill-indeterminate' : 'progress-fill'} ${isIndeterminate ? indeterminateFillStyles : fillStyles}`}\n style={isIndeterminate ? undefined : { width: `${percentage}%` }}\n />\n </div>\n </>\n )}\n </AriaProgressBar>\n );\n}\n","'use client';\n\nimport { style } from '@react-spectrum/s2/style' with { type: 'macro' };\n\nexport type BadgeVariant = 'completed' | 'running' | 'failed' | 'cancelled' | 'pending' | 'plum' | 'cucumber' | 'berry' | 'ginger' | 'peach';\n\nexport interface BadgeProps {\n variant?: BadgeVariant;\n children: React.ReactNode;\n}\n\nconst badgeStyles = style({\n paddingY: 4,\n paddingX: 12,\n borderRadius: 'lg',\n font: 'ui-sm',\n display: 'inline-block',\n backgroundColor: {\n variant: {\n completed: '--cucumber-100',\n running: '--ginger-100',\n failed: '--berry-100',\n cancelled: '--plum-100',\n pending: '--plum-100',\n plum: '--plum-100',\n cucumber: '--cucumber-100',\n berry: '--berry-100',\n ginger: '--ginger-100',\n peach: '--peach-100',\n }\n },\n color: {\n variant: {\n completed: '--cucumber-700',\n running: '--ginger-700',\n failed: '--berry-700',\n cancelled: '--plum-700',\n pending: '--plum-700',\n plum: '--plum-700',\n cucumber: '--cucumber-700',\n berry: '--berry-700',\n ginger: '--ginger-700',\n peach: '--peach-700',\n }\n }\n});\n\n/**\n * Badge component for displaying status or category with conditional colors\n * \n * @example\n * <Badge variant=\"completed\">Completed</Badge>\n * <Badge variant=\"cucumber\">Vegetable</Badge>\n */\nexport function Badge({ variant, children }: BadgeProps) {\n return (\n <span className={badgeStyles({ variant })}>\n {children}\n </span>\n );\n}\n","import { Button as AriaButton, ButtonProps as AriaButtonProps } from 'react-aria-components';\nimport CloseCircle from '@react-spectrum/s2/icons/CloseCircle';\nimport { focusRing, iconStyle, style } from '@react-spectrum/s2/style' with { type: 'macro' };\nimport { useIntl } from '../lib/i18n-context';\n\n// For props: https://react-spectrum.adobe.com/react-aria/Button.html#props\n// For styling: https://react-spectrum.adobe.com/react-aria/Button.html#styling\n\nexport interface CloseButtonProps extends Omit<AriaButtonProps, 'onPress'> {\n onClose: () => void;\n}\n\nconst closeButtonStyles = style({\n ...focusRing(),\n padding: 8,\n backgroundColor: {\n default: 'transparent',\n isHovered: '--yogurt-100',\n isPressed: '--yogurt-200'\n },\n borderStyle: 'none',\n borderRadius: 'lg',\n cursor: 'pointer',\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n forcedColors: {\n backgroundColor: 'ButtonFace',\n color: 'ButtonText',\n borderColor: 'ButtonBorder',\n borderWidth: 1,\n borderStyle: 'solid'\n }\n});\n\nexport const CloseButton = ({ onClose, ...props }: CloseButtonProps) => {\n const intl = useIntl();\n\n return (\n <AriaButton\n {...props}\n onPress={onClose}\n className={renderProps => closeButtonStyles(renderProps)}\n aria-label={intl.formatMessage({ id: 'ferment.detail.close' })}\n >\n <CloseCircle styles={iconStyle({ size: 'XL' })} />\n </AriaButton>\n );\n};\n","'use client';\n\nimport { Button, ComboBox as AriaComboBox, FieldError, Input, Label, ListBox, ListBoxItem, Popover, Text } from 'react-aria-components';\nimport type { Key } from 'react-aria-components';\nimport { focusRing, style } from '@react-spectrum/s2/style' with { type: 'macro' };\nimport ChevronDown from '@react-spectrum/s2/icons/ChevronDown';\n\nconst comboBoxContainerStyles = style({\n display: 'flex',\n flexDirection: 'column',\n gap: 4,\n minWidth: 192,\n});\n\nconst labelStyles = style({\n font: 'body',\n color: '--plum-700',\n});\n\nconst inputWrapperStyles = style({\n position: 'relative',\n display: 'flex',\n alignItems: 'center',\n});\n\nconst inputStyles = style({\n ...focusRing(),\n width: 'full',\n paddingX: 12,\n paddingY: 8,\n backgroundColor: {\n default: '--yogurt-100',\n isFocusVisible: '--yogurt-200',\n isDisabled: 'gray-100',\n },\n borderRadius: 'lg',\n borderWidth: 1,\n borderStyle: 'solid',\n borderColor: {\n default: '--yogurt-400',\n isFocusVisible: '--plum-600',\n isDisabled: 'gray-300',\n },\n font: 'body',\n color: {\n default: '--plum-700',\n isDisabled: 'gray-500',\n },\n outlineStyle: 'none',\n});\n\nconst buttonStyles = style({\n position: 'absolute',\n insetInlineEnd: 4,\n padding: 4,\n borderRadius: 'sm',\n backgroundColor: {\n default: 'transparent',\n isHovered: 'gray-200',\n },\n borderStyle: 'none',\n color: {\n default: 'gray-600',\n isDisabled: 'gray-400',\n },\n cursor: {\n default: 'pointer',\n isDisabled: 'default',\n },\n});\n\nconst popoverStyles = style({\n backgroundColor: '--yogurt-50',\n borderRadius: 'lg',\n borderWidth: 1,\n borderStyle: 'solid',\n borderColor: '--yogurt-400',\n boxShadow: 'elevated',\n marginTop: 4,\n maxHeight: 320,\n overflow: 'auto',\n isolation: 'isolate',\n});\n\nconst listBoxStyles = style({\n padding: 4,\n outline: 'none',\n});\n\nconst listBoxItemStyles = style({\n font: 'body',\n paddingX: 8,\n paddingY: 4,\n borderRadius: 'sm',\n cursor: {\n default: 'pointer',\n isDisabled: 'not-allowed',\n },\n backgroundColor: {\n default: 'transparent',\n isHovered: '--yogurt-200',\n isSelected: '--plum-200',\n isFocused: '--yogurt-200',\n isDisabled: '--yogurt-100',\n },\n color: {\n default: '--plum-700',\n isHovered: '--plum-800',\n isFocused: '--plum-800',\n isPressed: '--plum-900',\n isSelected: '--plum-700',\n isDisabled: 'gray-400',\n },\n outline: 'none',\n});\n\nconst descriptionStyles = style({\n font: 'detail',\n color: 'gray-600',\n});\n\nconst errorStyles = style({\n font: 'detail',\n color: '--berry-700',\n});\n\nexport interface ComboBoxItem {\n id: Key;\n label: string;\n textValue?: string;\n}\n\nexport interface ComboBoxProps {\n label?: string;\n description?: string;\n errorMessage?: string;\n isRequired?: boolean;\n isDisabled?: boolean;\n selectedKey?: Key | null;\n onSelectionChange?: (key: Key | null) => void;\n items: ComboBoxItem[];\n placeholder?: string;\n 'aria-label'?: string;\n inputValue?: string;\n onInputChange?: (value: string) => void;\n}\n\n/**\n * Generic ComboBox component for searchable single-selection.\n * \n * Uses React Aria Components ComboBox for accessible selection with filtering.\n * Reusable for any data type - countries, users, categories, etc.\n * \n * @example\n * ```tsx\n * const items = [\n * { id: 1, label: 'Apple' },\n * { id: 2, label: 'Banana' },\n * { id: 3, label: 'Orange' },\n * ];\n * \n * <ComboBox\n * label=\"Fruit\"\n * items={items}\n * selectedKey={selectedId}\n * onSelectionChange={setSelectedId}\n * placeholder=\"Select a fruit\"\n * />\n * ```\n */\nexport function ComboBox({\n label,\n description,\n errorMessage,\n isRequired = false,\n isDisabled = false,\n selectedKey,\n onSelectionChange,\n items,\n placeholder,\n 'aria-label': ariaLabel,\n inputValue: controlledInputValue,\n onInputChange: controlledOnInputChange,\n}: ComboBoxProps) {\n return (\n <AriaComboBox\n className={comboBoxContainerStyles}\n inputValue={controlledInputValue}\n onInputChange={controlledOnInputChange}\n selectedKey={selectedKey}\n onSelectionChange={onSelectionChange}\n isDisabled={isDisabled}\n isRequired={isRequired}\n aria-label={ariaLabel || label}\n >\n {label && <Label className={labelStyles}>{label}</Label>}\n <div className={inputWrapperStyles}>\n <Input className={inputStyles} placeholder={placeholder} />\n <Button className={buttonStyles}>\n <ChevronDown />\n </Button>\n </div>\n {description && !errorMessage && (\n <Text slot=\"description\" className={descriptionStyles}>\n {description}\n </Text>\n )}\n {errorMessage && <FieldError className={errorStyles}>{errorMessage}</FieldError>}\n <Popover className={popoverStyles}>\n <ListBox className={listBoxStyles} items={items}>\n {(item) => (\n <ListBoxItem\n key={item.id}\n id={item.id}\n textValue={item.textValue || item.label}\n className={listBoxItemStyles}\n >\n {item.label}\n </ListBoxItem>\n )}\n </ListBox>\n </Popover>\n </AriaComboBox>\n );\n}\n","'use client';\n\nimport {\n Button as AriaButton,\n Disclosure,\n DisclosureGroup as AriaDisclosureGroup,\n DisclosurePanel,\n DisclosureStateContext,\n Heading\n} from 'react-aria-components';\nimport ChevronRight from '@react-spectrum/s2/icons/ChevronRight';\nimport type { DisclosureGroupProps } from 'react-aria-components';\nimport { style, iconStyle, focusRing } from '@react-spectrum/s2/style' with { type: 'macro' };\nimport { useContext } from 'react';\n\nimport './DisclosureGroup.css';\n\n// Disclosure container - very thin grey border, full width button appearance\nconst disclosureContainerStyles = style({\n borderStyle: 'none',\n borderWidth: 0,\n borderColor: 'transparent',\n borderRadius: 'lg',\n overflow: 'hidden',\n width: 'full',\n backgroundColor: '--yogurt-100'\n});\n\n// Disclosure trigger button - blends seamlessly with container\nconst disclosureTriggerStyles = style({\n ...focusRing(),\n font: 'title',\n color: {\n default: '--plum-700',\n isHovered: '--plum-800',\n isFocusVisible: '--plum-800',\n isPressed: '--plum-900'\n },\n display: 'flex',\n alignItems: 'center',\n gap: 8,\n padding: 16,\n paddingX: 20,\n width: 'full',\n backgroundColor: {\n default: '--yogurt-100',\n isHovered: '--yogurt-200',\n isPressed: '--yogurt-300'\n },\n borderStyle: 'none',\n borderRadius: 'none',\n cursor: 'pointer'\n});\n\nconst disclosureHeaderStyles = style({\n margin: 0,\n});\n\n// Disclosure panel - white/light background, blends with button header\nconst disclosurePanelStyles = style({\n padding: {\n default: 0,\n isExpanded: 20,\n },\n backgroundColor: '--yogurt-50',\n borderTopWidth: 1,\n borderTopStyle: 'solid',\n borderColor: '--yogurt-300'\n});\n\nexport interface DisclosureItem {\n id: string;\n title: string;\n content: React.ReactNode;\n onPress?: () => void;\n}\n\ninterface CustomDisclosureGroupProps extends Omit<DisclosureGroupProps, 'children'> {\n items: DisclosureItem[];\n 'aria-label'?: string;\n}\n\n/**\n * Reusable DisclosureGroup component\n * Displays collapsible sections with consistent styling\n * \n * @example\n * <DisclosureGroup\n * items={[\n * {\n * id: 'section1',\n * title: 'Section 1',\n * content: <div>Content goes here</div>\n * }\n * ]}\n * />\n */\nexport function DisclosureGroup({ items, ...props }: CustomDisclosureGroupProps) {\n return (\n <AriaDisclosureGroup {...props} className={disclosureContainerStyles}>\n {items.map((item) => (\n <Disclosure key={item.id}>\n <DisclosureContents key={item.id} {...item} />\n </Disclosure>\n ))}\n </AriaDisclosureGroup>\n );\n}\n\nconst DisclosureContents = (item: DisclosureItem) => {\n let { isExpanded } = useContext(DisclosureStateContext)!;\n\n return (\n <>\n <Heading className={disclosureHeaderStyles}>\n <AriaButton\n slot=\"trigger\"\n className={(renderProps) =>\n `disclosure-chevron ${disclosureTriggerStyles(renderProps)}`\n }\n onPress={item.onPress}\n >\n <ChevronRight styles={iconStyle({ size: 'S' })} />\n {item.title}\n </AriaButton>\n </Heading>\n <DisclosurePanel className={disclosurePanelStyles({ isExpanded })}>\n {item.content}\n </DisclosurePanel>\n </>\n );\n}\n","'use client';\n\nimport {\n TextField as AriaTextField,\n Label,\n Text,\n} from 'react-aria-components';\nimport { style, } from '@react-spectrum/s2/style' with { type: 'macro' };\nimport {\n textFieldDescriptionStyles as labeledValueDescriptionStyles,\n textFieldErrorStyles as labeledValueErrorStyles,\n textFieldLabelStyles as labeledValueLabelStyles,\n} from './TextField';\n\nexport interface LabeledValueProps {\n label: string;\n error?: string;\n description?: string;\n children: React.ReactNode;\n}\n\nconst labeledValueStyles = style({\n display: 'flex',\n flexDirection: 'column',\n gap: 8,\n marginBottom: 20,\n});\n\nconst labeledValueValueStyles = style({\n font: 'body',\n color: '--plum-700',\n});\n\n\nexport function LabeledValue({ label, children, error, description, ...props }: LabeledValueProps) {\n return (\n <AriaTextField className={labeledValueStyles} {...props}>\n <Label className={labeledValueLabelStyles}>{label}</Label>\n <span className={labeledValueValueStyles}>\n {children}\n </span>\n {description && !error && (\n <Text slot=\"description\" className={labeledValueDescriptionStyles}>\n {description}\n </Text>\n )}\n {error && (\n <Text slot=\"errorMessage\" className={labeledValueErrorStyles}>\n {error}\n </Text>\n )}\n </AriaTextField>\n );\n}\n","import { Radio as AriaRadio, RadioGroup as AriaRadioGroup, type RadioGroupProps as AriaRadioGroupProps, type RadioProps as AriaRadioProps } from 'react-aria-components';\nimport { style, focusRing } from '@react-spectrum/s2/style' with { type: 'macro' };\n\nexport interface RadioGroupProps extends Omit<AriaRadioGroupProps, 'children'> {\n label: string;\n options: Array<{ id: string; label: string; value: string }>;\n error?: string;\n}\n\nexport interface RadioProps extends AriaRadioProps {\n children: React.ReactNode;\n}\n\nconst radioGroupStyles = style({\n display: 'flex',\n flexDirection: 'column',\n gap: 8,\n});\n\nconst labelStyles = style({\n font: 'body',\n fontWeight: 'medium',\n color: '--plum-700',\n marginBottom: 8,\n});\n\nconst radioContainerStyles = style({\n display: 'flex',\n flexDirection: 'column',\n gap: 12,\n});\n\nconst radioStyles = style({\n ...focusRing(),\n display: 'flex',\n alignItems: 'center',\n gap: 8,\n font: 'body',\n color: {\n default: '--plum-700',\n isSelected: '--plum-800',\n isHovered: '--plum-600',\n isDisabled: 'gray-400',\n },\n cursor: 'pointer',\n padding: 8,\n borderRadius: 'lg',\n backgroundColor: {\n default: 'transparent',\n isHovered: '--plum-50',\n },\n});\n\nconst radioButtonStyles = style({\n width: 20,\n height: 20,\n borderRadius: 'full',\n borderWidth: 2,\n borderStyle: 'solid',\n borderColor: {\n default: 'gray-400',\n isSelected: '--plum-500',\n isHovered: '--plum-300',\n isDisabled: 'gray-200',\n },\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n flexShrink: 0,\n backgroundColor: {\n default: 'layer-1',\n isDisabled: 'gray-100',\n },\n});\n\nconst radioInnerDotStyles = style({\n width: 10,\n height: 10,\n borderRadius: 'full',\n backgroundColor: '--plum-500',\n opacity: {\n default: 0,\n isSelected: 1,\n },\n});\n\nconst errorStyles = style({\n font: 'body-sm',\n color: '--berry-600',\n marginTop: 4,\n});\n\nexport function Radio({ children, ...props }: RadioProps) {\n return (\n <AriaRadio {...props} className={renderProps => radioStyles(renderProps)}>\n {renderProps => (\n <>\n <div className={radioButtonStyles(renderProps)}>\n <div className={radioInnerDotStyles(renderProps)} />\n </div>\n <span>{children}</span>\n </>\n )}\n </AriaRadio>\n );\n}\n\nexport function RadioGroup({ label, options, error, ...props }: RadioGroupProps) {\n return (\n <AriaRadioGroup {...props} className={radioGroupStyles}>\n <span className={labelStyles}>{label}</span>\n <div className={radioContainerStyles}>\n {options.map(option => (\n <Radio key={option.id} value={option.value}>\n {option.label}\n </Radio>\n ))}\n </div>\n {error && <span className={errorStyles}>{error}</span>}\n </AriaRadioGroup>\n );\n}\n","'use client';\n\nimport { SearchField as AriaSearchField, Input, Label, Button } from 'react-aria-components';\nimport Close from '@react-spectrum/s2/icons/Close';\nimport { focusRing, style } from '@react-spectrum/s2/style' with { type: 'macro' };\nimport { raw } from '../utils/styleMacro' with { type: 'macro' };\nimport Search from '@react-spectrum/s2/icons/Search';\n\n\nconst searchFieldContainerStyles = style({\n flex: {\n default: 'none',\n md: 1,\n },\n});\n\nconst searchFieldStyles = style({\n display: 'flex',\n flexDirection: 'column',\n gap: 4,\n});\n\nconst searchInputContainerStyles = style({\n position: 'relative',\n display: 'flex',\n alignItems: 'center',\n});\n\nconst searchInputStyles = style({\n ...focusRing(),\n width: 'full',\n padding: 8,\n paddingStart: 40,\n font: 'body',\n borderRadius: 'lg',\n borderWidth: 1,\n borderStyle: 'solid',\n borderColor: '--yogurt-400',\n backgroundColor: {\n default: '--yogurt-100',\n isHovered: '--yogurt-200',\n isFocusVisible: '--yogurt-200',\n },\n});\n\nconst labelStyles = style({\n font: 'body',\n color: '--plum-700',\n marginBottom: 4,\n});\n\nconst searchIconStyles = {\n position: 'absolute' as const,\n left: 12,\n top: '50%',\n transform: 'translateY(-50%)',\n pointerEvents: 'none' as const,\n color: '--yogurt-600',\n};\n\nconst clearButtonStyles = style({\n ...focusRing(),\n position: 'absolute',\n right: 8,\n top: '50%',\n transform: 'translateY(-50%)',\n padding: 4,\n backgroundColor: 'transparent',\n borderStyle: 'none',\n borderRadius: 'default',\n cursor: 'pointer',\n color: {\n default: '--yogurt-600',\n isHovered: '--yogurt-700',\n isPressed: '--yogurt-800',\n },\n});\n\nexport interface SearchFieldProps {\n value: string;\n onChange: (value: string) => void;\n label: string;\n placeholder: string;\n ariaLabel: string;\n}\n\n/**\n * Reusable SearchField component using React Aria Components\n * Styled with S2 design tokens and includes search icon\n * \n * @example\n * <SearchField\n * value={searchQuery}\n * onChange={setSearchTerm}\n * label=\"Search\"\n * placeholder=\"Search ferments...\"\n * ariaLabel=\"Search ferments by name or description\"\n * />\n */\nexport function SearchField({\n value,\n onChange,\n label,\n placeholder,\n ariaLabel,\n}: SearchFieldProps) {\n return (\n <div className={searchFieldContainerStyles}>\n <AriaSearchField\n value={value}\n onChange={onChange}\n className={searchFieldStyles}\n aria-label={ariaLabel}\n >\n {({ isEmpty }) => (\n <>\n <Label className={labelStyles}>{label}</Label>\n <div className={searchInputContainerStyles}>\n <div style={searchIconStyles}>\n <Search />\n </div>\n <Input className={(renderProps) => searchInputStyles(renderProps) + ' ' + raw('&::-webkit-search-cancel-button { display: none }', 'custom_layer')} placeholder={placeholder} />\n {!isEmpty && <Button className={clearButtonStyles} aria-label=\"Clear search\">\n <Close />\n </Button>}\n </div>\n </>\n )}\n </AriaSearchField>\n </div>\n );\n}\n","'use client';\n\nimport { useRouter } from 'next/navigation';\nimport {\n ToggleButton,\n ToggleButtonGroup,\n SelectionIndicator\n} from 'react-aria-components';\nimport { focusRing, style } from '@react-spectrum/s2/style' with { type: 'macro' };\nimport { useIntl } from '../lib/i18n-context';\nimport GlobeGrid from '@react-spectrum/s2/icons/GlobeGrid';\nimport ListIcon from '@react-spectrum/s2/icons/ViewList';\n\nconst segmentedControlStyles = style({\n display: 'flex',\n gap: 0,\n padding: 4,\n backgroundColor: '--yogurt-200',\n borderRadius: 'lg',\n borderWidth: 1,\n borderStyle: 'solid',\n borderColor: '--yogurt-400',\n});\n\nconst toggleButtonStyles = style({\n ...focusRing(),\n position: 'relative',\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n gap: 8,\n paddingX: 16,\n paddingY: 8,\n font: 'body',\n color: {\n default: '--plum-700',\n isHovered: '--plum-800',\n isFocusVisible: '--plum-800',\n isPressed: '--plum-900'\n },\n backgroundColor: 'transparent',\n borderStyle: 'none',\n borderRadius: 'default',\n cursor: 'pointer',\n zIndex: 1,\n '--iconPrimary': {\n type: 'color',\n value: {\n default: '--plum-700',\n isHovered: '--plum-800',\n isFocusVisible: '--plum-800',\n isPressed: '--plum-900'\n },\n }\n});\n\nconst selectionIndicatorStyles = style({\n position: 'absolute',\n inset: 0,\n borderRadius: 'default',\n borderWidth: 1,\n borderStyle: 'solid',\n borderColor: 'gray-300',\n boxShadow: 'elevated',\n zIndex: -1,\n color: {\n isDisabled: 'gray-400',\n forcedColors: 'ButtonText'\n },\n backgroundColor: {\n default: '--plum-300',\n isHovered: '--plum-400',\n isFocusVisibile: '--plum-400',\n isPressed: '--plum-400',\n isDisabled: 'gray-100',\n forcedColors: 'ButtonFace'\n },\n});\n\ninterface SegmentedControlProps {\n value: 'map' | 'list';\n}\n\n/**\n * SegmentedControl for Map/List view toggle\n * Uses RAC ToggleButtonGroup for accessible segmented control\n */\nexport function SegmentedControl({ value }: SegmentedControlProps) {\n const intl = useIntl();\n const router = useRouter();\n\n const handleSelectionChange = (newValue: 'map' | 'list') => {\n if (newValue === 'map') {\n router.push('/');\n } else {\n router.push('/ferments');\n }\n };\n\n return (\n <ToggleButtonGroup\n selectionMode=\"single\"\n selectedKeys={new Set([value])}\n disallowEmptySelection\n onSelectionChange={(keys) => {\n const selected = Array.from(keys)[0] as 'map' | 'list';\n handleSelectionChange(selected);\n }}\n aria-label={intl.formatMessage({ id: 'nav.viewToggle.ariaLabel' })}\n className={segmentedControlStyles}\n >\n <ToggleButton\n id=\"map\"\n className={(renderProps) => toggleButtonStyles(renderProps)}\n aria-label={intl.formatMessage({ id: 'nav.map' })}\n >\n {(renderProps) => (\n <>\n <SelectionIndicator className={selectionIndicatorStyles(renderProps)} />\n <GlobeGrid aria-hidden=\"true\" />\n <span>{intl.formatMessage({ id: 'nav.map' })}</span>\n </>\n )}\n </ToggleButton>\n\n <ToggleButton\n id=\"list\"\n className={(renderProps) => toggleButtonStyles(renderProps)}\n aria-label={intl.formatMessage({ id: 'nav.list' })}\n >\n {(renderProps) => (\n <>\n <SelectionIndicator className={selectionIndicatorStyles(renderProps)} />\n <ListIcon aria-hidden=\"true\" />\n <span>{intl.formatMessage({ id: 'nav.list' })}</span>\n </>\n )}\n </ToggleButton>\n </ToggleButtonGroup>\n );\n}\n","'use client';\n\nimport {\n Select as AriaSelect,\n SelectProps,\n Label,\n Button,\n SelectValue,\n Popover,\n ListBox,\n ListBoxItem\n} from 'react-aria-components';\nimport { focusRing, style } from '@react-spectrum/s2/style' with { type: 'macro' };\nimport ChevronDown from '@react-spectrum/s2/icons/ChevronDown';\n\nconst selectContainerStyles = style({\n display: 'flex',\n flexDirection: 'column',\n gap: 4,\n minWidth: 200\n});\n\nconst labelStyles = style({\n font: 'body',\n color: '--plum-700',\n});\n\nconst buttonStyles = style({\n ...focusRing(),\n paddingX: 12,\n paddingY: 8,\n backgroundColor: {\n default: '--yogurt-100',\n isHovered: '--yogurt-200',\n isFocusVisible: '--yogurt-200',\n isPressed: '--yogurt-300'\n },\n borderRadius: 'lg',\n borderWidth: 1,\n borderStyle: 'solid',\n borderColor: '--yogurt-400',\n font: 'body',\n color: {\n default: '--plum-700',\n isHovered: '--plum-800',\n isFocused: '--plum-800',\n isPressed: '--plum-900',\n },\n cursor: 'pointer',\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'space-between',\n gap: 8,\n minWidth: 200\n});\n\nconst popoverStyles = style({\n backgroundColor: '--yogurt-50',\n borderRadius: 'lg',\n borderWidth: 1,\n borderStyle: 'solid',\n borderColor: '--yogurt-400',\n boxShadow: 'elevated',\n marginTop: 4,\n maxHeight: 300,\n overflow: 'auto',\n isolation: 'isolate',\n});\n\nconst listBoxStyles = style({\n padding: 4,\n outline: 'none'\n});\n\nconst listBoxItemStyles = style({\n font: 'body',\n paddingX: 8,\n paddingY: 4,\n borderRadius: 'sm',\n cursor: {\n default: 'pointer',\n isDisabled: 'not-allowed'\n },\n backgroundColor: {\n default: 'transparent',\n isHovered: '--yogurt-200',\n isSelected: '--plum-200',\n isFocused: '--yogurt-200',\n isDisabled: '--yogurt-100'\n },\n color: {\n default: '--plum-700',\n isHovered: '--plum-800',\n isFocused: '--plum-800',\n isPressed: '--plum-900',\n isSelected: '--plum-700',\n isDisabled: 'gray-400'\n },\n outline: 'none'\n});\n\nexport interface SelectOption {\n id: string;\n label: string;\n value: string | null;\n isDisabled?: boolean;\n}\n\ninterface CustomSelectProps extends Omit<SelectProps<SelectOption>, 'children'> {\n label: string;\n options: SelectOption[];\n placeholder?: string;\n}\n\n/**\n * Reusable Select component following RAC pattern\n * Label is inside the Select wrapper for proper a11y\n */\nexport function Select({ label, options, placeholder, ...props }: CustomSelectProps) {\n return (\n <AriaSelect {...props} className={selectContainerStyles}>\n <Label className={labelStyles}>{label}</Label>\n <Button className={buttonStyles}>\n <SelectValue />\n <ChevronDown aria-hidden=\"true\" />\n </Button>\n <Popover className={popoverStyles}>\n <ListBox className={listBoxStyles} items={options}>\n {(item) => (\n <ListBoxItem\n key={item.id}\n id={item.id}\n textValue={item.label}\n isDisabled={item.isDisabled}\n className={listBoxItemStyles}\n >\n {item.label}\n </ListBoxItem>\n )}\n </ListBox>\n </Popover>\n </AriaSelect>\n );\n}\n","'use client';\n\nimport { ReactNode } from 'react';\nimport { style } from '@react-spectrum/s2/style' with { type: 'macro' };\n\nexport interface StatCardProps {\n title: string;\n value: ReactNode;\n description?: string;\n}\n\nconst cardStyles = style({\n backgroundColor: 'layer-1',\n borderRadius: 'xl',\n padding: 24,\n borderWidth: 1,\n borderStyle: 'solid',\n borderColor: '--plum-200',\n display: 'flex',\n flexDirection: 'column',\n gap: 12,\n alignItems: 'center',\n textAlign: 'center'\n});\n\nconst cardTitleStyles = style({\n font: 'title-lg',\n color: '--plum-700',\n margin: 0\n});\n\nconst cardValueStyles = style({\n font: 'heading-2xl',\n color: '--plum-700',\n});\n\nconst cardDescStyles = style({\n font: 'body',\n color: '--plum-700',\n margin: 0\n});\n\n/**\n * StatCard component for displaying dashboard statistics\n * \n * @example\n * <StatCard \n * title=\"Total Sources\"\n * value={42}\n * description=\"Active scraping sources\"\n * />\n * \n * @example\n * // With icon as value\n * <StatCard \n * title=\"System Status\"\n * value={<CheckmarkCircle />}\n * description=\"All systems operational\"\n * />\n */\nexport function StatCard({ title, value, description }: StatCardProps) {\n return (\n <div className={cardStyles}>\n <h3 className={cardTitleStyles}>{title}</h3>\n <div className={cardValueStyles}>{value}</div>\n {description && <p className={cardDescStyles}>{description}</p>}\n </div>\n );\n}\n","import { Switch as AriaSwitch, SwitchProps as AriaSwitchProps } from 'react-aria-components';\nimport { focusRing, style } from '@react-spectrum/s2/style' with { type: 'macro' };\n\n// For props: https://react-spectrum.adobe.com/react-aria/Switch.html#props\n// For styling: https://react-spectrum.adobe.com/react-aria/Switch.html#styling\n\nconst switchContainerStyles = style({\n ...focusRing(),\n display: 'flex',\n alignItems: 'center',\n gap: 8,\n paddingEnd: 2,\n cursor: 'pointer',\n font: 'ui-lg',\n color: {\n default: '--plum-700',\n isHovered: '--plum-800',\n isFocusVisible: '--plum-800',\n isPressed: '--plum-900'\n },\n borderRadius: 'full'\n});\n\nconst switchTrackStyles = style({\n width: 44,\n height: 24,\n borderRadius: 'full',\n padding: 2,\n display: 'flex',\n alignItems: 'center',\n backgroundColor: {\n default: '--yogurt-400',\n isSelected: '--plum-500',\n isDisabled: 'disabled'\n },\n borderStyle: {\n forcedColors: 'solid'\n },\n borderColor: {\n forcedColors: 'ButtonBorder'\n },\n borderWidth: {\n forcedColors: 1\n }\n});\n\nconst switchThumbStyles = style({\n width: 20,\n height: 20,\n borderRadius: 'full',\n backgroundColor: {\n default: 'white',\n forcedColors: 'ButtonText'\n },\n transform: {\n default: 'translateX(0)',\n isSelected: 'translateX(22px)'\n }\n});\n\nexport interface SwitchProps extends Omit<AriaSwitchProps, 'children'> {\n children?: React.ReactNode;\n}\n\nexport const Switch = ({ children, ...props }: SwitchProps) => {\n return (\n <AriaSwitch\n {...props}\n className={renderProps => switchContainerStyles(renderProps)}\n >\n {renderProps => (\n <>\n <div className={switchTrackStyles(renderProps)}>\n <div className={switchThumbStyles(renderProps)} />\n </div>\n {children}\n </>\n )}\n </AriaSwitch>\n );\n};","import { focusRing, style } from '@react-spectrum/s2/style' with { type: 'macro' };\nimport { Tabs as AriaTabs, TabList as AriaTabList, Tab as AriaTab, TabPanel as AriaTabPanel } from 'react-aria-components';\nimport type { TabListProps, TabPanelProps, TabProps, TabsProps } from 'react-aria-components';\n\nconst tabsStyles = style({\n display: 'flex',\n flexDirection: 'column',\n gap: 0\n});\n\nconst tabListStyles = style({\n display: 'flex',\n gap: 4,\n borderBottomWidth: 2,\n borderBottomStyle: 'solid',\n borderBottomColor: '--plum-200',\n marginBottom: 24\n});\n\nconst tabStyles = style({\n ...focusRing(),\n paddingX: 20,\n paddingY: 12,\n font: 'body',\n fontWeight: {\n isSelected: 'bold'\n },\n color: {\n default: '--plum-700',\n isSelected: '--plum-800',\n isHovered: '--plum-800',\n isDisabled: '--plum-300'\n },\n backgroundColor: {\n default: 'transparent',\n isHovered: '--plum-50',\n isSelected: '--plum-100'\n },\n borderWidth: 0,\n borderBottomWidth: 2,\n borderStyle: 'solid',\n borderColor: {\n default: 'transparent',\n isSelected: '--plum-700',\n isHovered: '--plum-300'\n },\n cursor: {\n default: 'pointer',\n isDisabled: 'not-allowed'\n },\n transitionProperty: 'all',\n transitionDuration: '200ms'\n});\n\nconst tabPanelStyles = style({\n paddingY: 0,\n outlineStyle: 'none'\n});\n\nexport function Tabs({ children, ...props }: TabsProps) {\n return (\n <AriaTabs className={tabsStyles} {...props}>\n {children}\n </AriaTabs>\n );\n}\n\nexport function TabList<T extends object>({ children, ...props }: TabListProps<T>) {\n return (\n <AriaTabList className={tabListStyles} {...props}>\n {children}\n </AriaTabList>\n );\n}\n\nexport function Tab({ children, ...props }: TabProps) {\n return (\n <AriaTab className={tabStyles} {...props}>\n {children}\n </AriaTab>\n );\n}\n\nexport function TabPanel({ children, ...props }: TabPanelProps) {\n return (\n <AriaTabPanel className={tabPanelStyles} {...props}>\n {children}\n </AriaTabPanel>\n );\n}\n","'use client';\n\nimport {\n TextArea as AriaTextArea,\n TextField as AriaTextField,\n Label,\n} from 'react-aria-components';\nimport { style } from '@react-spectrum/s2/style' with { type: 'macro' };\nimport { textFieldErrorStyles, textFieldLabelStyles, type TextFieldProps, textFieldStyles } from './TextField';\nimport { textFieldInputStyles } from '../utils/styleUtils' with { type: 'macro' };\nimport { useRef, useEffect } from 'react';\n\nexport interface TextAreaProps extends Omit<TextFieldProps, 'type'> { }\n\nconst textareaStyles = style({\n ...textFieldInputStyles(),\n resize: 'none',\n minHeight: 75, // ~3 lines\n maxHeight: '75vh',\n overflowY: 'auto',\n});\n\nexport function TextArea({ label, error, placeholder, value, ...props }: TextAreaProps) {\n const textareaRef = useRef<HTMLTextAreaElement>(null);\n\n // Auto-grow on value change\n useEffect(() => {\n const textarea = textareaRef.current;\n if (!textarea) return;\n\n // Reset height to recalculate\n textarea.style.height = '75px';\n\n // Set to scrollHeight (content height)\n const newHeight = Math.min(textarea.scrollHeight, window.innerHeight * 0.75);\n textarea.style.height = `${newHeight}px`;\n }, [value]);\n\n return (\n <AriaTextField className={textFieldStyles} {...props} value={value}>\n <Label className={textFieldLabelStyles}>{label}</Label>\n <AriaTextArea\n ref={textareaRef}\n className={textareaStyles}\n placeholder={placeholder}\n />\n {error && <div className={textFieldErrorStyles}>{error}</div>}\n </AriaTextField>\n );\n}\n","/* Checkbox styles for svg checked state */\n\n.checkbox-checkmark {\n width: 70%;\n height: 70%;\n fill: none;\n stroke: white;\n stroke-width: 2;\n stroke-linecap: round;\n stroke-linejoin: round;\n transition: stroke-dashoffset 150ms;\n}\n\n.checkbox-checkmark-path {\n stroke-dasharray: 22;\n stroke-dashoffset: 66;\n transition: stroke-dashoffset 150ms;\n}\n\n.checkbox-checkmark-path.checkbox-checkmark-selected {\n stroke-dashoffset: 44;\n}","/* Progress bar animations and transitions */\n.progress-fill {\n transition: width 200ms ease-in-out;\n}\n\n.progress-fill-indeterminate {\n animation: progress-indeterminate 1.5s cubic-bezier(0.4, 0, 0.6, 1) infinite;\n}\n\n@keyframes progress-indeterminate {\n 0% {\n transform: translateX(-100%);\n }\n\n 100% {\n transform: translateX(350%);\n }\n}","/**\n * HealthCheck Component - Animations Only\n * All other styles are in S2 style macros\n */\n\n/* Chevron icon rotation on expansion */\n.disclosure-chevron[aria-expanded=\"true\"] svg {\n transform: rotate(90deg);\n}\n\n.disclosure-chevron svg {\n transition: transform 200ms;\n}\n\n@keyframes slideDown {\n from {\n opacity: 0;\n transform: translateY(-10px);\n }\n\n to {\n opacity: 1;\n transform: translateY(0);\n }\n}\n\n@keyframes slideUp {\n from {\n opacity: 1;\n transform: translateY(0);\n }\n\n to {\n opacity: 0;\n transform: translateY(-10px);\n }\n}"],"names":[],"version":3,"file":"module.css.map"}
1
+ {"mappings":"ACMsB;EAAA;;;;EAAA;;;;EAUF;;;;EAAA;;;;EAAA;;;;EAiBE;;;;EAAA;;;;EAAA;;;;EAcI;;;;ECjCL;;;;;;EAAA;;;;EAAA;;;;EAAA;;;;;EAAA;;;;;EAAA;;;;EAAA;;;;;EAAA;;;;EAAA;;;;EC2CI;;;;EAsDE;;;;;EAeJ;;;;EAAA;;;;ECxHC;;;;EAAA;;;;EAOK;;;;ECkCT;;;;EA6BF;;;;;EAkBC;;;;;EAAA;;;;EAiBQ;;;;EAQF;;;;EAAA;;;;EAAA;;;;EAAA;;;;EAaG;;;;EAAA;;;;ECxHL;;;;EAiBL;;;;EAAA;;;;EAAA;;;;EAAA;;;;EAAA;;;;EAAA;;;;EAAA;;;;EAAA;;;;EAuCC;;;;EAAA;;;;EClDC;;;;EAcY;;;;EAAA;;;;ECvBZ;;;;EAAA;;;;EAAA;;;;EAAA;;;;EAAA;;;;EAAA;;;;;;EAAA;;;;EAAA;;;;EAAA;;;;EAAA;;;;ECoCO;;;;EAAA;;;;ECxCK;;;;EAkBZ;;;;EAAA;;;;EA0BC;;;;EAAA;;;;EAoBC;;;;EA6CI;;;;EAKN;;;;ECvGc;;;;EAAA;;;;EAAA;;;;EAWF;;;;EAAA;;;;EAAA;;;;EAAA;;;;EAAA;;;;EAAA;;;;EA8BF;;;;EAAA;;;;EAAA;;;;EAAA;;;;EAAA;;;;EA+DE;;;;EAAA;;;;ECrGL;;;;ECAP;;;;EAAA;;;;EAAA;;;;EAaA;;;;EAqBM;;;;EAAA;;;;EAAA;;;;EAAA;;;;EAAA;;;;EAAA;;;;EAsBE;;;;EAAA;;;;EAAA;;;;EAAA;;;;EAWR;;;;EAAA;;;;EC5DM;;;;EAAA;;;;EAiBN;;;;EAeM;;;;EAAA;;;;EAAA;;;;EAAA;;;;EAAA;;;;EAAA;;;;ECpCC;;;;EAAA;;;;EAAA;;;;EAAA;;;;EAAA;;;;EAAA;;;;EAAA;;;;EAgCM;;;;EAAA;;;;EAAA;;;;EAAA;;;;EAAA;;;;EAAA;;;;EAAA;;;;EAAA;;;;EAAA;;;;EAAA;;;;EAAA;;;;EAAA;;;;EAAA;;;;;;EC7BZ;;;;EAAA;;;;EAAA;;;;EAAA;;;;EAAA;;;;;EAAA;;;;EAAA;;;;EAAA;;;;EA6BC;;;;EAAA;;;;EAAA;;;;EAAA;;;;EAAA;;;;EAAA;;;;EAAA;;;;EAaA;;;;EAAA;;;;EAKI;;;;EAAA;;;;EAAA;;;;EAAA;;;;EAAA;;;;EAAA;;;;EAAA;;;;EAAA;;;;EAAA;;;;EAAA;;;;EAAA;;;;EAAA;;;;EC/DP;;;;EAAA;;;;EAAA;;;;EAAA;;;;EAAA;;;;EAAA;;;;EAAA;;;;EAAA;;;;EAAA;;;;EAAA;;;;EAAA;;;;EAAA;;;;EAcK;;;;EAMA;;;;EAAA;;;;EAAA;;;;EAKD;;;;EAAA;;;;EAAA;;;;EAAA;;;;EC5BO;;;;EAAA;;;;EAAA;;;;EAAA;;;;EAiBJ;;;;EAAA;;;;EAAA;;;;EAAA;;;;EAAA;;;;EAAA;;;;EAAA;;;;EAAA;;;;EAAA;;;;EAAA;;;;EAuBA;;;;EAAA;;;;EAAA;;;;EAAA;;;;EAAA;;;;EAAA;;;;EAAA;;;;EAAA;;;;EAAA;;;;EC1CP;;;;EAAA;;;;EAAA;;;;EAMG;;;;EAAA;;;;EAAA;;;;EAAA;;;;EASJ;;;;EAAA;;;;EAAA;;;;EAAA;;;;EAAA;;;;EAAA;;;;EAAA;;;;EAAA;;;;EAAA;;;;EAAA;;;;EAAA;;;;EAAA;;;;EAAA;;;;EAAA;;;;EAAA;;;;EAAA;;;;EAAA;;;;EAAA;;;;EAAA;;;;EAAA;;;;EAAA;;;;EAAA;;;;EAAA;;;;EAmCK;;;;EAAA;;;;EAAA;;;;EC1CA;;;;EAAA;;;;EAAA;;;;EAAA;;;;EAAA;;;;EAAA;;;;EAAA;;;;EAAA;;;;EAAA;;;;EAAA;;;;EAAA;;;;EAAA;;;;EAAA;;;;EAAA;;;;EAAA;;;;EAAA;;;;EAAA;;;;EAAA;;;;EAAA;;;;EAAA;;;;EAAA;;;;EAAA;;;;EAAA;;;;EAAA;;;;EAAA;;;;EAAA;;;;EAAA;;;;EAAA;;;;EAAA;;;;EAAA;;;;;AnBIH;EYGA;;;;EAAA;;;;EAAA;;;;EIUI;;;;EAAA;;;;ECvBM;;;;ECaZ;;;;EAAA;;;;EAAA;;;;ECPK;;;;EAAA;;;;;AnBIH;EgBOI;;;;EAAA;;;;EAAA;;;;EAMA;;;;EAAA;;;;EAAA;;;;ECvBM;;;;ECaZ;;;;;AlBHE;EAAA;IAAA;;;;;;AAAA;EAAA;IAAA;;;;;;AAiBE;EgBVE;;;;EAAA;;;;EAAA;;;;EAMA;;;;EAAA;;;;EAAA;;;;EAKD;;;;;AhBDD;EgBJE;;;;EAAA;;;;EAAA;;;;EAKD;;;;;AhBDD;EgBJE;;;;EAAA;;;;EAAA;;;;EAKD;;;;;AhBDD;EAAA;;;;;AAAA;EAAA;;;;;AAAA;EAAA;;;;;ACnBD;EAAA;IAAA;;;;IawCY;;;;IAAA;;;;IG/BP;;;;IAAA;;;;IAAA;;;;IAAA;;;;IAAA;;;;IAAA;;;;IAuBA;;;;;;AG5C1B;;;;;;;;;;;AAWA;;;;;;AAMA;;;;AClBA;;;;AAIA;;;;AAIA;;;;;;;;;;ACHA;;;;AAIA;;;;AAIA;;;;;;;;;;;;AAYA;;;;;;;;;;;;AT6FwF;;AAAA;EAAA;IAAA","sources":["27d1e9fc0b161a21","packages/shared/src/components/AlertDialog.tsx","packages/shared/src/components/Button.tsx","packages/shared/src/components/Autocomplete.tsx","packages/shared/src/components/AutocompleteTable.tsx","packages/shared/src/components/Table.tsx","packages/shared/src/components/Checkbox.tsx","packages/shared/src/components/ProgressBar.tsx","packages/shared/src/components/Badge.tsx","packages/shared/src/components/CloseButton.tsx","packages/shared/src/components/ComboBox.tsx","packages/shared/src/components/DisclosureGroup.tsx","packages/shared/src/components/LabeledValue.tsx","packages/shared/src/components/RadioGroup.tsx","packages/shared/src/components/SearchField.tsx","packages/shared/src/components/SegmentedControl.tsx","packages/shared/src/components/Select.tsx","packages/shared/src/components/StatCard.tsx","packages/shared/src/components/Switch.tsx","packages/shared/src/components/Tabs.tsx","packages/shared/src/components/TextArea.tsx","packages/shared/src/components/Checkbox.css","packages/shared/src/components/ProgressBar.css","packages/shared/src/components/DisclosureGroup.css"],"sourcesContent":["@import \"9f47f68ba38c295a\";\n@import \"78c590a309b0e6a4\";\n@import \"290522a232eb340f\";\n@import \"9d168f2695c440b5\";\n@import \"cc4d3a5fac51363d\";\n@import \"8ee7d6e801b40a1c\";\n@import \"6ffa14505a299e4e\";\n@import \"cfef988437953ae9\";\n@import \"93c21ad3845ca137\";\n@import \"83429286ceb3be13\";\n@import \"03dd1cfb5962a09d\";\n@import \"620de91e79ad0a16\";\n@import \"d274ac5a14987bf9\";\n@import \"416838a95541a7c4\";\n@import \"53f941c4c340fa03\";\n@import \"82593e9a11ceb790\";\n@import \"4312b6d61177a486\";\n@import \"7f7804fa3c921faf\";\n@import \"29e82be3069c1c2c\";\n@import \"26b1a04880d0efb1\";\n@import \"f315d14c1596594f\";\n@import \"245a17a9caf6065d\";\n@import \"03b25ce5fcd826d5\";\n@import \"f64b1199c5ac10c2\";\n@import \"d00995e4bf421650\";\n@import \"418c33e40e8fa307\";\n@import \"77a381a4ad5e4deb\";\n@import \"79a47b3e11bde76b\";\n@import \"4c61b37e83b6cbaf\";\n@import \"7d6c90f6382f216d\";\n@import \"d5a82419c43c0258\";\n@import \"4c5c6d90d8125894\";\n@import \"d7830e0fdb5f5a4f\";\n@import \"3cb9bcfb6f0038f8\";\n@import \"8d4f769c29e4ee31\";\n@import \"e8338bb3ae3fb1c4\";\n@import \"541891615c093f21\";\n@import \"3415552572bd8d79\";\n@import \"30bf95091f7ade51\";\n@import \"f03216825356c24c\";\n@import \"a035a1ff61c82329\";\n@import \"f0b45c7a5a4ee6b4\";\n@import \"00d20b13f70db88f\";\n@import \"99348462226d32b0\";\n@import \"f133ffb8107f1499\";\n@import \"060090694d7abb5e\";\n@import \"02d1fda45f088142\";\n@import \"0be6be6f1b4df772\";\n@import \"d000b87b862d640a\";\n@import \"99cf12a0bc5155d4\";\n@import \"3dea62b5608bc4c7\";\n@import \"00dffe07cf30c480\";\n@import \"daa2dcfcc6aba2ec\";\n@import \"22d59f7061eee5c3\";\n@import \"c730c2c683575e83\";\n@import \"4c4abb4dd24ed78d\";\n@import \"55d42732ed05bd7c\";\n@import \"7e7d0afbf7be7aaf\";\n@import \"fe26295011b80084\";\n@import \"98f373d7d990b86e\";\n@import \"44556bb5ffa970fa\";\n@import \"ffb67edd6d59f4d0\";\n@import \"3f8a3d39101fb8de\";\n@import \"da5d3570a6be5108\";\n@import \"a81b95f6ba098d94\";\n@import \"6e45401afedcc213\";\n@import \"823e68b0820e33b0\";\n@import \"6098b6422a6b5107\";\n@import \"e704ae4b0ea5b6a4\";\n@import \"18ca83a63b402953\";\n@import \"9934fabeca5dc14b\";\n@import \"08e05744d70ceb2e\";\n@import \"51f566c4383bc873\";\n@import \"00f37031e59ae452\";\n@import \"b2e8234656a0acab\";\n@import \"1c127e7148e69ee6\";\n@import \"31b2213af713491b\";\n@import \"c313bd17239b6dfb\";\n@import \"cc3cacc59937fd97\";\n@import \"1b5034e53b6b6e9d\";\n@import \"f43b41886b283acc\";\n@import \"b30e558e03268eb5\";\n@import \"16fa3c2822ce8fa6\";\n@import \"6cc8a6d86b48a0f8\";\n@import \"2d5249b468c9ed81\";\n@import \"d69789ae2771f37d\";\n@import \"a750f611c47db198\";\n@import \"2243763201ee6943\";\n@import \"2c30d3e83234d14f\";\n@import \"e9c2f06a78f0fa1b\";\n@import \"1629b57b41de7f33\";\n@import \"d38717759287a5cb\";\n@import \"5046bf9ea1029bc4\";\n@import \"a33499d27b9fcd76\";\n@import \"a31990ea1642f273\";\n@import \"d1b031cf4bda7480\";\n@import \"e81d7eb3988d206b\";\n@import \"6f65c616b892c898\";\n@import \"adda47912e5baae7\";\n@import \"d9ef614c1a51f3a0\";\n@import \"36dbb656eeb11098\";\n@import \"d3b3b5097317263d\";\n@import \"c7bfffb20d48ffa6\";\n@import \"75d222754bbb0b8f\";\n@import \"b79287f289978582\";\n@import \"55cf679aaecacd02\";\n@import \"a4a1c07b3ebdf826\";\n@import \"5a19908ab4aad173\";\n","import { Button } from './Button';\nimport { Dialog, Heading, Modal, ModalOverlay } from 'react-aria-components';\nimport { style } from '@react-spectrum/s2/style' with { type: 'macro' };\nimport { TextField } from './TextField';\nimport { useState } from 'react';\n\nconst overlayStyles = style({\n position: 'fixed',\n inset: 0,\n backgroundColor: 'transparent-black-500',\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n isolation: 'isolate',\n});\n\nconst modalStyles = style({\n backgroundColor: 'layer-1',\n borderRadius: 'xl',\n boxShadow: 'elevated',\n padding: 24,\n width: {\n default: 'calc(100vw - 32px)',\n sm: 400,\n md: 500\n },\n maxWidth: 500,\n transform: {\n entering: 'scale(0.95)',\n default: 'scale(1)'\n },\n});\n\nconst headingStyles = style({\n font: 'heading-xl',\n color: 'heading',\n margin: 0,\n marginBottom: 12\n});\n\nconst messageStyles = style({\n font: 'body',\n color: 'neutral',\n margin: 0,\n marginBottom: 24\n});\n\nconst buttonGroupStyles = style({\n display: 'flex',\n gap: 12,\n justifyContent: 'end'\n});\n\nexport interface AlertDialogProps {\n isOpen: boolean;\n onClose: () => void;\n title: string;\n message: string;\n variant?: 'danger' | 'warning' | 'info' | 'success';\n confirmLabel?: string;\n cancelLabel?: string;\n onConfirm: () => void | Promise<void>;\n showCancel?: boolean;\n children?: React.ReactNode; // Optional custom content (e.g., Switch, Checkbox)\n}\n\nexport function AlertDialog({\n isOpen,\n onClose,\n title,\n message,\n variant = 'info',\n confirmLabel = 'OK',\n cancelLabel = 'Cancel',\n onConfirm,\n showCancel = true,\n children\n}: AlertDialogProps) {\n const [isProcessing, setIsProcessing] = useState(false);\n\n const handleConfirm = async () => {\n setIsProcessing(true);\n try {\n await onConfirm();\n onClose();\n } finally {\n setIsProcessing(false);\n }\n };\n\n // Map variant to button variant\n const buttonVariant = variant === 'danger' ? 'danger' :\n variant === 'success' ? 'primary' :\n 'primary';\n\n return (\n <ModalOverlay isOpen={isOpen} onOpenChange={(open) => !open && onClose()} className={overlayStyles}>\n <Modal className={modalStyles}>\n <Dialog>\n {({ close }) => (\n <>\n <Heading slot=\"title\" className={headingStyles}>\n {title}\n </Heading>\n <p className={messageStyles}>{message}</p>\n {children && (\n <div className={style({ marginBottom: 24 })}>\n {children}\n </div>\n )}\n <div className={buttonGroupStyles}>\n {showCancel && (\n <Button\n variant=\"secondary\"\n size=\"M\"\n onPress={close}\n isDisabled={isProcessing}\n >\n {cancelLabel}\n </Button>\n )}\n <Button\n variant={buttonVariant}\n size=\"M\"\n onPress={handleConfirm}\n isDisabled={isProcessing}\n >\n {isProcessing ? 'Processing...' : confirmLabel}\n </Button>\n </div>\n </>\n )}\n </Dialog>\n </Modal>\n </ModalOverlay>\n );\n}\n\nexport interface PromptDialogProps {\n isOpen: boolean;\n onClose: () => void;\n title: string;\n message: string;\n inputLabel: string;\n inputPlaceholder?: string;\n confirmLabel?: string;\n cancelLabel?: string;\n onConfirm: (value: string) => void | Promise<void>;\n validator?: (value: string) => string | null;\n}\n\nexport function PromptDialog({\n isOpen,\n onClose,\n title,\n message,\n inputLabel,\n inputPlaceholder = '',\n confirmLabel = 'OK',\n cancelLabel = 'Cancel',\n onConfirm,\n validator\n}: PromptDialogProps) {\n const [value, setValue] = useState('');\n const [error, setError] = useState<string | null>(null);\n const [isProcessing, setIsProcessing] = useState(false);\n\n const handleConfirm = async () => {\n // Validate\n if (validator) {\n const validationError = validator(value);\n if (validationError) {\n setError(validationError);\n return;\n }\n }\n\n setIsProcessing(true);\n try {\n await onConfirm(value);\n setValue('');\n setError(null);\n onClose();\n } finally {\n setIsProcessing(false);\n }\n };\n\n const handleClose = () => {\n setValue('');\n setError(null);\n onClose();\n };\n\n return (\n <ModalOverlay isOpen={isOpen} onOpenChange={(open) => !open && handleClose()} className={overlayStyles}>\n <Modal className={modalStyles}>\n <Dialog>\n {({ close }) => (\n <>\n <Heading slot=\"title\" className={headingStyles}>\n {title}\n </Heading>\n <p className={messageStyles}>{message}</p>\n <div className={style({ marginBottom: 24 })}>\n <TextField\n label={inputLabel}\n value={value}\n onChange={(newValue) => {\n setValue(newValue);\n setError(null);\n }}\n placeholder={inputPlaceholder}\n error={error || undefined}\n autoFocus\n />\n </div>\n <div className={buttonGroupStyles}>\n <Button\n variant=\"secondary\"\n size=\"M\"\n onPress={() => {\n setValue('');\n setError(null);\n close();\n }}\n isDisabled={isProcessing}\n >\n {cancelLabel}\n </Button>\n <Button\n variant=\"primary\"\n size=\"M\"\n onPress={handleConfirm}\n isDisabled={isProcessing}\n >\n {isProcessing ? 'Processing...' : confirmLabel}\n </Button>\n </div>\n </>\n )}\n </Dialog>\n </Modal>\n </ModalOverlay>\n );\n}\n","import { Button as AriaButton, ButtonProps as AriaButtonProps } from 'react-aria-components';\nimport { focusRing, style } from '@react-spectrum/s2/style' with { type: 'macro' };\n\n// For props: https://react-spectrum.adobe.com/react-aria/Button.html#props\n// For styling: https://react-spectrum.adobe.com/react-aria/Button.html#styling\n// For conditional styling: https://react-spectrum.adobe.com/beta/s2/styling.html#conditional-styles\n\nexport interface ButtonProps extends AriaButtonProps {\n children?: React.ReactNode;\n variant?: 'primary' | 'secondary' | 'danger' | 'navigation';\n size?: 'S' | 'M' | 'L';\n}\n\n// Primary variant styles\nconst buttonStyles = style({\n ...focusRing(),\n font: {\n default: 'body',\n size: {\n S: 'body-sm',\n L: 'body-lg',// or `body` too?\n },\n },\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n gap: {\n default: 8,\n size: {\n S: 4,\n },\n },\n paddingY: {\n default: 12,\n size: {\n S: 8,\n L: 16,\n },\n variant: {\n navigation: {\n default: 4\n }\n }\n },\n paddingStart: {\n default: 16,\n size: {\n S: 12,\n L: 24,\n },\n variant: {\n navigation: {\n default: 8\n }\n }\n },\n paddingEnd: {\n default: 16,\n size: {\n S: 12,\n L: 24,\n },\n variant: {\n navigation: 12\n }\n },\n width: {\n variant: {\n navigation: 'fit'\n }\n },\n color: {\n variant: {\n secondary: {\n default: '--plum-700',\n },\n danger: {\n default: 'white',\n },\n navigation: {\n default: '--plum-700',\n }\n },\n forcedColors: 'ButtonText',\n isDisabled: {\n default: 'gray-400',\n forcedColors: 'GrayText',\n },\n },\n backgroundColor: {\n default: '--plum-300',\n variant: {\n primary: {\n default: '--plum-300',\n isHovered: '--plum-400',\n isFocusVisibile: '--plum-400',\n isPressed: '--plum-400',\n },\n secondary: {\n default: '--yogurt-200',\n isHovered: '--yogurt-300',\n isFocusVisibile: '--yogurt-300',\n isPressed: '--yogurt-400',\n },\n navigation: {\n default: 'transparent',\n isHovered: '--yogurt-200',\n isFocusVisibile: '--yogurt-200',\n isPressed: '--yogurt-300',\n },\n danger: {\n default: '--berry-500',\n isHovered: '--berry-600',\n isFocusVisibile: '--berry-600',\n isPressed: '--berry-700',\n },\n },\n forcedColors: 'ButtonFace',\n isDisabled: {\n default: 'gray-100',\n isDisabled: 'GrayText',\n },\n },\n borderRadius: 'lg',\n borderStyle: {\n default: 'none',\n forcedColors: 'solid'\n },\n borderColor: {\n forcedColors: 'ButtonBorder'\n },\n borderWidth: {\n forcedColors: 1\n },\n cursor: {\n default: 'pointer',\n isDisabled: 'not-allowed'\n }\n});\n\nexport const Button = ({\n children,\n variant = 'primary',\n size = 'M',\n className,\n ...props\n}: ButtonProps) => {\n return (\n <AriaButton\n {...props}\n className={renderProps => `${className || ''} ` + buttonStyles({ ...renderProps, size, variant })}\n >\n {children}\n </AriaButton>\n );\n};\n","import { useState, useMemo } from 'react';\nimport {\n SearchField as AriaSearchField,\n Autocomplete as AriaAutocomplete,\n Input,\n Label,\n ListBox,\n ListBoxItem,\n useFilter,\n Popover\n} from 'react-aria-components';\nimport { focusRing, style } from '@react-spectrum/s2/style' with { type: 'macro' };\nimport Search from '@react-spectrum/s2/icons/Search';\nimport CheckmarkCircle from '@react-spectrum/s2/icons/CheckmarkCircle';\nimport type { Selection } from 'react-aria-components';\n\nconst containerStyles = style({\n display: 'flex',\n flexDirection: 'column',\n gap: 4,\n width: 'full',\n});\n\nconst labelStyles = style({\n font: 'body',\n color: '--plum-700',\n});\n\nconst searchFieldStyles = style({\n display: 'flex',\n flexDirection: 'column',\n gap: 4,\n});\n\nconst inputContainerStyles = style({\n position: 'relative',\n display: 'flex',\n alignItems: 'center',\n});\n\nconst inputStyles = style({\n ...focusRing(),\n width: 'full',\n padding: 8,\n paddingStart: 40,\n font: 'body',\n borderRadius: 'lg',\n borderWidth: 1,\n borderStyle: 'solid',\n borderColor: '--yogurt-400',\n backgroundColor: {\n default: '--yogurt-100',\n isHovered: '--yogurt-200',\n isFocusVisible: '--yogurt-200',\n },\n});\n\nconst searchIconStyles = style({\n position: 'absolute',\n left: 12,\n top: '50%',\n transform: 'translateY(-50%)',\n pointerEvents: 'none',\n color: '--yogurt-600',\n});\n\nconst popoverStyles = style({\n backgroundColor: '--yogurt-50',\n borderRadius: 'lg',\n borderWidth: 1,\n borderStyle: 'solid',\n borderColor: '--yogurt-400',\n boxShadow: 'elevated',\n marginTop: 4,\n maxHeight: 300,\n overflow: 'auto',\n isolation: 'isolate',\n // width: 'full',\n // minWidth: 300,\n});\n\nconst listBoxStyles = style({\n padding: 4,\n outline: 'none',\n});\n\nconst listBoxItemStyles = style({\n ...focusRing(),\n font: 'body',\n paddingX: 8,\n paddingY: 8,\n borderRadius: 'sm',\n cursor: 'pointer',\n display: 'flex',\n alignItems: 'center',\n gap: 8,\n backgroundColor: {\n default: 'transparent',\n isHovered: '--yogurt-200',\n isFocused: '--yogurt-200',\n isPressed: '--yogurt-300',\n },\n color: {\n default: '--plum-700',\n isHovered: '--plum-800',\n isFocused: '--plum-800',\n isPressed: '--plum-900',\n },\n outline: 'none',\n});\n\nconst selectedItemStyles = style({\n backgroundColor: {\n default: '--plum-100',\n isHovered: '--plum-200',\n isFocused: '--plum-200',\n },\n color: '--plum-900',\n});\n\nconst checkboxStyles = style({\n width: 16,\n height: 16,\n flexShrink: 0,\n});\n\nconst itemTextStyles = style({\n flex: 1,\n overflow: 'hidden',\n textOverflow: 'ellipsis',\n whiteSpace: 'nowrap',\n});\n\nconst errorStyles = style({\n font: 'body-sm',\n color: '--berry-600',\n});\n\nexport interface AutocompleteItem {\n id: string | number;\n name: string;\n [key: string]: any;\n}\n\nexport interface AutocompleteProps<T extends AutocompleteItem> {\n items: T[];\n selectedKeys?: Selection;\n onSelectionChange?: (keys: Selection) => void;\n selectionMode?: 'none' | 'single' | 'multiple';\n label: string;\n placeholder?: string;\n ariaLabel?: string;\n error?: string;\n getItemText?: (item: T) => string;\n}\n\n/**\n * Autocomplete component using React Aria SearchField + ListBox\n * \n * Features:\n * - SearchField for filtering items\n * - Optional checkboxes for multi-selection\n * - Shows both selected and unselected items when filtered\n * - Selected items highlighted with background color\n * - Keyboard navigation (arrow keys, enter, escape)\n * - Accessible (ARIA labels, focus management)\n * \n * @example\n * ```tsx\n * // Single select\n * <Autocomplete\n * items={sources}\n * selectedKeys={selectedKey}\n * onSelectionChange={setSelectedKey}\n * selectionMode=\"single\"\n * label=\"Select Source\"\n * placeholder=\"Search sources...\"\n * />\n * \n * // Multi select\n * <Autocomplete\n * items={sources}\n * selectedKeys={selectedKeys}\n * onSelectionChange={setSelectedKeys}\n * selectionMode=\"multiple\"\n * label=\"Select Sources\"\n * placeholder=\"Search sources...\"\n * />\n * \n * // No selection (just filtering)\n * <Autocomplete\n * items={sources}\n * selectionMode=\"none\"\n * label=\"Search Sources\"\n * placeholder=\"Search sources...\"\n * />\n * ```\n */\nexport function Autocomplete<T extends AutocompleteItem>({\n items,\n selectedKeys,\n onSelectionChange,\n selectionMode = 'none',\n label,\n placeholder,\n ariaLabel,\n error,\n getItemText = (item) => item.name,\n}: AutocompleteProps<T>) {\n const [inputValue, setInputValue] = useState('');\n const { contains } = useFilter({ sensitivity: 'base' });\n\n // Filter items based on input value\n const filteredItems = useMemo(() => {\n if (!inputValue) return items;\n const searchLower = inputValue.toLowerCase();\n return items.filter((item) =>\n getItemText(item).toLowerCase().includes(searchLower)\n );\n }, [items, inputValue, getItemText]);\n\n // Sort to show selected items first when in selection mode\n const sortedItems = useMemo(() => {\n if (selectionMode === 'none' || !selectedKeys) return filteredItems;\n\n return [...filteredItems].sort((a, b) => {\n const aSelected = selectedKeys === 'all' || selectedKeys.has(String(a.id));\n const bSelected = selectedKeys === 'all' || selectedKeys.has(String(b.id));\n if (aSelected && !bSelected) return -1;\n if (!aSelected && bSelected) return 1;\n return 0;\n });\n }, [filteredItems, selectedKeys, selectionMode]);\n\n const showCheckboxes = selectionMode !== 'none';\n\n return (\n <div className={containerStyles}>\n <AriaAutocomplete\n filter={contains}\n inputValue={inputValue}\n onInputChange={setInputValue}\n >\n <AriaSearchField\n className={searchFieldStyles}\n aria-label={ariaLabel || label}\n >\n <Label className={labelStyles}>{label}</Label>\n <div className={inputContainerStyles}>\n <div className={searchIconStyles}><Search /></div>\n <Input\n className={inputStyles}\n placeholder={placeholder}\n />\n </div>\n </AriaSearchField>\n\n <ListBox\n className={listBoxStyles}\n items={sortedItems}\n selectionMode={selectionMode}\n selectedKeys={selectedKeys}\n onSelectionChange={onSelectionChange}\n aria-label={ariaLabel || `${label} options`}\n >\n {(item) => {\n const isSelected = selectedKeys === 'all' || (selectedKeys && selectedKeys.has(String(item.id)));\n return (\n <ListBoxItem\n key={item.id}\n id={String(item.id)}\n textValue={getItemText(item)}\n className={(renderProps) =>\n `${listBoxItemStyles(renderProps)} ${isSelected ? selectedItemStyles(renderProps) : ''}`\n }\n >\n {showCheckboxes && (\n <div className={checkboxStyles}>\n {isSelected && <CheckmarkCircle />}\n </div>\n )}\n <span className={itemTextStyles}>{getItemText(item)}</span>\n </ListBoxItem>\n );\n }}\n </ListBox>\n\n {error && <div className={errorStyles}>{error}</div>}\n </AriaAutocomplete>\n </div>\n );\n}\n","import { useMemo } from 'react';\nimport type { Selection } from 'react-aria-components';\nimport { Autocomplete, type AutocompleteItem } from './Autocomplete';\nimport { Table, type ColumnDef } from './Table';\nimport { style } from '@react-spectrum/s2/style' with { type: 'macro' };\n\nconst containerStyles = style({\n display: 'flex',\n flexDirection: 'column',\n gap: 16,\n width: 'full',\n});\n\nconst tableContainerStyles = style({\n maxHeight: 384,\n overflow: 'auto',\n});\n\nexport interface AutocompleteTableProps<T extends AutocompleteItem> {\n // Autocomplete props\n allItems: T[];\n selectedKeys: Selection;\n onSelectionChange: (keys: Selection) => void;\n selectionMode?: 'single' | 'multiple';\n searchLabel: string;\n searchPlaceholder?: string;\n getItemText?: (item: T) => string;\n\n // Table props\n columns: ColumnDef<T>[];\n tableLabel: string;\n}\n\n/**\n * Composite component combining Autocomplete and Table\n * Useful for search-and-select workflows where selected items are displayed in a table\n * \n * Features:\n * - Autocomplete search field at top\n * - Table below showing selected items\n * - Filters all items in autocomplete\n * - Shows only selected items in table\n * - Scrollable table with max height of 384px\n * \n * @example\n * ```tsx\n * <AutocompleteTable\n * allItems={allSources}\n * selectedKeys={selectedSourceIds}\n * onSelectionChange={setSelectedSourceIds}\n * selectionMode=\"multiple\"\n * searchLabel=\"Search Sources\"\n * searchPlaceholder=\"Search by name or URL...\"\n * columns={[\n * { key: 'name', label: 'Name', isRowHeader: true },\n * { key: 'domain', label: 'Domain' },\n * { key: 'actions', label: 'Actions', align: 'end' },\n * ]}\n * tableLabel=\"Selected Sources\"\n * />\n * ```\n */\nexport function AutocompleteTable<T extends AutocompleteItem>({\n allItems,\n selectedKeys,\n onSelectionChange,\n selectionMode = 'multiple',\n searchLabel,\n searchPlaceholder,\n getItemText,\n columns,\n tableLabel,\n}: AutocompleteTableProps<T>) {\n // Filter to show only selected items in table\n const selectedItems = useMemo(() => {\n if (selectedKeys === 'all') return allItems;\n if (!selectedKeys || selectedKeys.size === 0) return [];\n\n return allItems.filter(item => selectedKeys.has(String(item.id)));\n }, [allItems, selectedKeys]);\n\n return (\n <div className={containerStyles}>\n <Autocomplete\n items={allItems}\n selectedKeys={selectedKeys}\n onSelectionChange={onSelectionChange}\n selectionMode={selectionMode}\n label={searchLabel}\n placeholder={searchPlaceholder}\n getItemText={getItemText}\n />\n\n <div className={tableContainerStyles}>\n <Table\n columns={columns}\n data={selectedItems}\n ariaLabel={tableLabel}\n />\n </div>\n </div>\n );\n}\n","import {\n Cell,\n Column,\n Row,\n Table as AriaTable,\n TableBody,\n TableHeader,\n type Key,\n type SortDescriptor\n} from 'react-aria-components';\nimport { focusRing, style } from '@react-spectrum/s2/style' with { type: 'macro' };\nimport { Checkbox } from './Checkbox';\nimport { ProgressBar } from './ProgressBar';\nimport { ReactNode, useRef, useEffect } from 'react';\n\nexport interface ColumnDef<T> {\n key: string;\n label: string;\n renderCell: (item: T) => ReactNode;\n width?: string;\n isRowHeader?: boolean;\n align?: 'start' | 'center' | 'end';\n}\n\nexport interface TableProps<T> {\n data: T[];\n columns: ColumnDef<T>[];\n onRowAction?: (key: Key) => void;\n ariaLabel: string;\n sortDescriptor?: SortDescriptor;\n onSortChange?: (descriptor: SortDescriptor) => void;\n selectionMode?: 'none' | 'single' | 'multiple';\n selectedKeys?: Set<Key>;\n onSelectionChange?: (keys: Set<Key>) => void;\n onLoadMore?: () => void;\n isLoadingMore?: boolean;\n}\n\nconst tableContainerStyles = style({\n backgroundColor: 'layer-1',\n borderRadius: 'xl',\n borderWidth: 1,\n borderStyle: 'solid',\n borderColor: '--plum-200',\n overflow: 'hidden'\n});\n\nconst tableStyles = style({\n width: 'full',\n borderCollapse: 'collapse'\n});\n\nconst tableHeaderStyles = style({\n backgroundColor: '--yogurt-200',\n borderBottomWidth: 1,\n borderBottomStyle: 'solid',\n borderBottomColor: '--plum-200'\n});\n\nconst columnHeaderStyles = style({\n padding: 16,\n textAlign: {\n default: 'start',\n align: {\n start: 'start',\n center: 'center',\n end: 'end',\n },\n },\n font: 'title-lg',\n color: '--plum-700',\n cursor: {\n allowsSorting: 'pointer'\n }\n});\n\nconst rowStyles = style({\n ...focusRing(),\n backgroundColor: {\n default: 'transparent',\n isHovered: '--yogurt-100',\n isSelected: '--plum-100',\n isFocusVisible: '--yogurt-100'\n },\n cursor: {\n default: 'default',\n onRowAction: 'pointer',\n selectionMode: {\n single: 'pointer',\n multiple: 'pointer'\n }\n }\n});\n\nconst cellStyles = style({\n padding: 16,\n textAlign: {\n default: 'start',\n align: {\n start: 'start',\n center: 'center',\n end: 'end',\n },\n },\n font: 'body',\n color: '--plum-700',\n borderBottomWidth: 1,\n borderBottomStyle: 'solid',\n borderBottomColor: '--plum-100'\n});\n\nconst checkboxCellStyles = style({\n padding: 16,\n width: 48,\n borderBottomWidth: 1,\n borderBottomStyle: 'solid',\n borderBottomColor: '--plum-100'\n});\n\nconst emptyStateStyles = style({\n padding: 48,\n textAlign: 'center',\n font: 'body',\n color: '--plum-600',\n});\n\nconst loadingStyles = style({\n padding: 24,\n display: 'flex',\n justifyContent: 'center'\n});\n\nconst scrollTriggerStyles = style({\n height: 1,\n pointerEvents: 'none'\n});\n\n/**\n * Reusable Table component using React Aria Components\n * \n * Features:\n * - Collection-based API for better performance\n * - Built-in virtualization support (via RAC)\n * - Keyboard navigation\n * - Screen reader support\n * - Optional sorting\n * - Optional row selection\n * - Optional row actions (clickable rows)\n * - Checkbox column for multiple selection\n * - Hover and selected states\n * \n * @example\n * ```tsx\n * const columns: ColumnDef<Run>[] = [\n * { key: 'id', label: 'ID', renderCell: (run) => `#${run.id}` },\n * { key: 'status', label: 'Status', renderCell: (run) => <Badge variant={run.status}>{run.status}</Badge> }\n * ];\n * \n * <Table\n * data={runs}\n * columns={columns}\n * ariaLabel=\"Scraper runs\"\n * selectionMode=\"multiple\"\n * selectedKeys={selectedIds}\n * onSelectionChange={setSelectedIds}\n * />\n * ```\n */\nexport function Table<T extends { id: number | string }>({\n data,\n columns,\n onRowAction,\n ariaLabel,\n sortDescriptor,\n onSortChange,\n selectionMode = 'none',\n selectedKeys,\n onSelectionChange,\n onLoadMore,\n isLoadingMore\n}: TableProps<T>) {\n const observerTarget = useRef<HTMLDivElement>(null);\n\n // Infinite scroll observer\n useEffect(() => {\n if (!onLoadMore) return;\n\n const observer = new IntersectionObserver(\n (entries) => {\n if (entries[0].isIntersecting && !isLoadingMore) {\n onLoadMore();\n }\n },\n { threshold: 0.1, rootMargin: '100px' }\n );\n\n if (observerTarget.current) {\n observer.observe(observerTarget.current);\n }\n\n return () => observer.disconnect();\n }, [onLoadMore, isLoadingMore]);\n\n return (\n <>\n <div className={tableContainerStyles}>\n <AriaTable\n aria-label={ariaLabel}\n selectionMode={selectionMode}\n selectedKeys={selectedKeys}\n onSelectionChange={onSelectionChange as any}\n onRowAction={onRowAction}\n sortDescriptor={sortDescriptor}\n onSortChange={onSortChange}\n className={tableStyles}\n >\n <TableHeader className={tableHeaderStyles}>\n {selectionMode === 'multiple' && (\n <Column className={columnHeaderStyles({ align: 'center', alignItems: 'center' })}>\n <Checkbox slot=\"selection\" size=\"S\" />\n </Column>\n )}\n {columns.map((column) => (\n <Column\n key={column.key}\n id={column.key}\n isRowHeader={column.isRowHeader}\n allowsSorting={!!onSortChange}\n className={columnHeaderStyles({ align: column.align })}\n >\n {column.label}\n </Column>\n ))}\n </TableHeader>\n <TableBody\n items={data}\n renderEmptyState={() => (\n <div className={emptyStateStyles}>\n No data available\n </div>\n )}\n >\n {(item) => (\n <Row\n key={item.id}\n id={item.id}\n className={(renderProps) => rowStyles({\n ...renderProps,\n onRowAction: !!onRowAction,\n selectionMode\n })}\n >\n {selectionMode === 'multiple' && (\n <Cell className={checkboxCellStyles}>\n <Checkbox slot=\"selection\" size=\"S\" />\n </Cell>\n )}\n {columns.map((column) => (\n <Cell key={column.key} className={cellStyles({ align: column.align })}>\n {column.renderCell(item)}\n </Cell>\n ))}\n </Row>\n )}\n </TableBody>\n </AriaTable>\n </div>\n\n {/* Infinite scroll trigger */}\n {onLoadMore && <div ref={observerTarget} className={scrollTriggerStyles} />}\n\n {/* Loading indicator */}\n {isLoadingMore && (\n <div className={loadingStyles}>\n <ProgressBar isIndeterminate aria-label=\"Loading more items\" />\n </div>\n )}\n </>\n );\n}\n\n","import { Checkbox as AriaCheckbox, type CheckboxProps as AriaCheckboxProps } from 'react-aria-components';\nimport { focusRing, style } from '@react-spectrum/s2/style' with { type: 'macro' };\nimport './Checkbox.css';\n\nexport interface CheckboxProps extends Omit<AriaCheckboxProps, 'className' | 'style'> {\n /**\n * The size of the Checkbox.\n * @default 'M'\n */\n size?: 'S' | 'M' | 'L';\n}\n\nconst checkboxStyles = style({\n display: 'flex',\n position: 'relative',\n alignItems: 'center',\n gap: 8,\n font: 'body',\n color: {\n default: '--plum-700',\n isDisabled: 'disabled'\n },\n cursor: {\n default: 'pointer',\n isDisabled: 'default'\n },\n disableTapHighlight: true\n});\n\nconst boxStyles = style({\n ...focusRing(),\n size: {\n default: 20,\n size: {\n S: 16,\n M: 20,\n L: 24\n }\n },\n flexShrink: 0,\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n borderWidth: 2,\n borderStyle: 'solid',\n borderRadius: 'sm',\n transition: 'default',\n backgroundColor: {\n default: 'layer-1',\n isSelected: {\n default: '--plum-600',\n isHovered: '--plum-700',\n isPressed: '--plum-800'\n },\n isDisabled: {\n default: 'gray-100',\n isSelected: 'gray-400'\n }\n },\n borderColor: {\n default: '--plum-400',\n isHovered: '--plum-500',\n isPressed: '--plum-600',\n isSelected: 'transparent',\n isDisabled: 'gray-300'\n }\n});\n\nconst dashStyles = style({\n width: '60%',\n height: 2,\n backgroundColor: 'white',\n borderRadius: 'sm'\n});\n\n/**\n * Checkbox component for selection within tables and forms.\n * Simplified version based on React Spectrum S2 Checkbox.\n * \n * @example\n * ```tsx\n * <Checkbox isSelected={selected} onChange={setSelected}>\n * Subscribe to newsletter\n * </Checkbox>\n * \n * // In table header/cell (no label)\n * <Checkbox slot=\"selection\" />\n * ```\n */\nexport function Checkbox({ size = 'M', children, ...props }: CheckboxProps) {\n return (\n <AriaCheckbox\n {...props}\n className={(renderProps) => checkboxStyles(renderProps)}\n >\n {(renderProps) => {\n const { isSelected, isIndeterminate } = renderProps;\n\n return (\n <>\n <div className={boxStyles({ ...renderProps, isSelected: isSelected || isIndeterminate, size })}>\n {isIndeterminate ? (\n <div className={dashStyles} />\n ) : isSelected ? (\n <svg viewBox=\"0 0 18 18\" aria-hidden=\"true\" className=\"checkbox-checkmark\">\n <polyline points=\"2 9 7 14 16 4\" className=\"checkbox-checkmark-path checkbox-checkmark-selected\" />\n </svg>\n ) : null}\n </div>\n {children}\n </>\n );\n }}\n </AriaCheckbox>\n );\n}\n","import { ProgressBar as AriaProgressBar } from 'react-aria-components';\nimport { style } from '@react-spectrum/s2/style' with { type: 'macro' };\nimport './ProgressBar.css';\n\nconst progressBarStyles = style({\n display: 'flex',\n flexDirection: 'column',\n gap: 4,\n width: 'full',\n});\n\nconst labelStyles = style({\n font: 'body',\n color: '--plum-700',\n display: 'flex',\n justifyContent: 'space-between',\n});\n\nconst trackStyles = style({\n height: 6,\n backgroundColor: '--yogurt-200',\n borderRadius: 'full',\n overflow: 'hidden',\n position: 'relative',\n});\n\nconst fillStyles = style({\n height: 'full',\n backgroundColor: '--plum-500',\n borderRadius: 'full',\n});\n\nconst indeterminateFillStyles = style({\n height: 'full',\n backgroundColor: '--plum-500',\n borderRadius: 'full',\n width: '40%',\n});\n\ninterface ProgressBarProps {\n label?: string;\n value?: number;\n maxValue?: number;\n isIndeterminate?: boolean;\n showValueLabel?: boolean;\n 'aria-label'?: string;\n}\n\n/**\n * ProgressBar Component\n * \n * Accessible progress indicator using React Aria Components.\n * Supports both determinate (with value) and indeterminate (loading) states.\n * \n * @example\n * // Determinate progress\n * <ProgressBar label=\"Loading...\" value={50} maxValue={100} />\n * \n * @example\n * // Indeterminate progress\n * <ProgressBar label=\"Loading...\" isIndeterminate />\n */\nexport function ProgressBar({\n label,\n value = 0,\n maxValue = 100,\n isIndeterminate = false,\n showValueLabel = true,\n 'aria-label': ariaLabel,\n}: ProgressBarProps) {\n return (\n <AriaProgressBar\n value={isIndeterminate ? undefined : value}\n maxValue={maxValue}\n isIndeterminate={isIndeterminate}\n aria-label={ariaLabel || label}\n className={progressBarStyles}\n >\n {({ percentage, valueText }) => (\n <>\n {label && (\n <div className={labelStyles}>\n <span>{label}</span>\n {!isIndeterminate && showValueLabel && <span>{valueText}</span>}\n </div>\n )}\n <div className={trackStyles}>\n <div\n className={`${isIndeterminate ? 'progress-fill-indeterminate' : 'progress-fill'} ${isIndeterminate ? indeterminateFillStyles : fillStyles}`}\n style={isIndeterminate ? undefined : { width: `${percentage}%` }}\n />\n </div>\n </>\n )}\n </AriaProgressBar>\n );\n}\n","import { style } from '@react-spectrum/s2/style' with { type: 'macro' };\n\nexport type BadgeVariant = 'completed' | 'running' | 'failed' | 'cancelled' | 'pending' | 'plum' | 'cucumber' | 'berry' | 'ginger' | 'peach';\n\nexport interface BadgeProps {\n variant?: BadgeVariant;\n children: React.ReactNode;\n}\n\nconst badgeStyles = style({\n paddingY: 4,\n paddingX: 12,\n borderRadius: 'lg',\n font: 'ui-sm',\n display: 'inline-block',\n backgroundColor: {\n variant: {\n completed: '--cucumber-100',\n running: '--ginger-100',\n failed: '--berry-100',\n cancelled: '--plum-100',\n pending: '--plum-100',\n plum: '--plum-100',\n cucumber: '--cucumber-100',\n berry: '--berry-100',\n ginger: '--ginger-100',\n peach: '--peach-100',\n }\n },\n color: {\n variant: {\n completed: '--cucumber-700',\n running: '--ginger-700',\n failed: '--berry-700',\n cancelled: '--plum-700',\n pending: '--plum-700',\n plum: '--plum-700',\n cucumber: '--cucumber-700',\n berry: '--berry-700',\n ginger: '--ginger-700',\n peach: '--peach-700',\n }\n }\n});\n\n/**\n * Badge component for displaying status or category with conditional colors\n * \n * @example\n * <Badge variant=\"completed\">Completed</Badge>\n * <Badge variant=\"cucumber\">Vegetable</Badge>\n */\nexport function Badge({ variant, children }: BadgeProps) {\n return (\n <span className={badgeStyles({ variant })}>\n {children}\n </span>\n );\n}\n","import { Button as AriaButton, ButtonProps as AriaButtonProps } from 'react-aria-components';\nimport CloseCircle from '@react-spectrum/s2/icons/CloseCircle';\nimport { focusRing, iconStyle, style } from '@react-spectrum/s2/style' with { type: 'macro' };\nimport { useIntl } from '../lib/i18n-context';\n\n// For props: https://react-spectrum.adobe.com/react-aria/Button.html#props\n// For styling: https://react-spectrum.adobe.com/react-aria/Button.html#styling\n\nexport interface CloseButtonProps extends Omit<AriaButtonProps, 'onPress'> {\n onClose: () => void;\n}\n\nconst closeButtonStyles = style({\n ...focusRing(),\n padding: 8,\n backgroundColor: {\n default: 'transparent',\n isHovered: '--yogurt-100',\n isPressed: '--yogurt-200'\n },\n borderStyle: 'none',\n borderRadius: 'lg',\n cursor: 'pointer',\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n forcedColors: {\n backgroundColor: 'ButtonFace',\n color: 'ButtonText',\n borderColor: 'ButtonBorder',\n borderWidth: 1,\n borderStyle: 'solid'\n }\n});\n\nexport const CloseButton = ({ onClose, ...props }: CloseButtonProps) => {\n const intl = useIntl();\n\n return (\n <AriaButton\n {...props}\n onPress={onClose}\n className={renderProps => closeButtonStyles(renderProps)}\n aria-label={intl.formatMessage({ id: 'ferment.detail.close' })}\n >\n <CloseCircle styles={iconStyle({ size: 'XL' })} />\n </AriaButton>\n );\n};\n","import { Button, ComboBox as AriaComboBox, FieldError, Input, Label, ListBox, ListBoxItem, Popover, Text } from 'react-aria-components';\nimport type { Key } from 'react-aria-components';\nimport { focusRing, style } from '@react-spectrum/s2/style' with { type: 'macro' };\nimport ChevronDown from '@react-spectrum/s2/icons/ChevronDown';\n\nconst comboBoxContainerStyles = style({\n display: 'flex',\n flexDirection: 'column',\n gap: 4,\n minWidth: 192,\n});\n\nconst labelStyles = style({\n font: 'body',\n color: '--plum-700',\n});\n\nconst inputWrapperStyles = style({\n position: 'relative',\n display: 'flex',\n alignItems: 'center',\n});\n\nconst inputStyles = style({\n ...focusRing(),\n width: 'full',\n paddingX: 12,\n paddingY: 8,\n backgroundColor: {\n default: '--yogurt-100',\n isFocusVisible: '--yogurt-200',\n isDisabled: 'gray-100',\n },\n borderRadius: 'lg',\n borderWidth: 1,\n borderStyle: 'solid',\n borderColor: {\n default: '--yogurt-400',\n isFocusVisible: '--plum-600',\n isDisabled: 'gray-300',\n },\n font: 'body',\n color: {\n default: '--plum-700',\n isDisabled: 'gray-500',\n },\n outlineStyle: 'none',\n});\n\nconst buttonStyles = style({\n position: 'absolute',\n insetInlineEnd: 4,\n padding: 4,\n borderRadius: 'sm',\n backgroundColor: {\n default: 'transparent',\n isHovered: 'gray-200',\n },\n borderStyle: 'none',\n color: {\n default: 'gray-600',\n isDisabled: 'gray-400',\n },\n cursor: {\n default: 'pointer',\n isDisabled: 'default',\n },\n});\n\nconst popoverStyles = style({\n backgroundColor: '--yogurt-50',\n borderRadius: 'lg',\n borderWidth: 1,\n borderStyle: 'solid',\n borderColor: '--yogurt-400',\n boxShadow: 'elevated',\n marginTop: 4,\n maxHeight: 320,\n overflow: 'auto',\n isolation: 'isolate',\n});\n\nconst listBoxStyles = style({\n padding: 4,\n outline: 'none',\n});\n\nconst listBoxItemStyles = style({\n font: 'body',\n paddingX: 8,\n paddingY: 4,\n borderRadius: 'sm',\n cursor: {\n default: 'pointer',\n isDisabled: 'not-allowed',\n },\n backgroundColor: {\n default: 'transparent',\n isHovered: '--yogurt-200',\n isSelected: '--plum-200',\n isFocused: '--yogurt-200',\n isDisabled: '--yogurt-100',\n },\n color: {\n default: '--plum-700',\n isHovered: '--plum-800',\n isFocused: '--plum-800',\n isPressed: '--plum-900',\n isSelected: '--plum-700',\n isDisabled: 'gray-400',\n },\n outline: 'none',\n});\n\nconst descriptionStyles = style({\n font: 'detail',\n color: 'gray-600',\n});\n\nconst errorStyles = style({\n font: 'detail',\n color: '--berry-700',\n});\n\nexport interface ComboBoxItem {\n id: Key;\n label: string;\n textValue?: string;\n}\n\nexport interface ComboBoxProps {\n label?: string;\n description?: string;\n errorMessage?: string;\n isRequired?: boolean;\n isDisabled?: boolean;\n selectedKey?: Key | null;\n onSelectionChange?: (key: Key | null) => void;\n items: ComboBoxItem[];\n placeholder?: string;\n 'aria-label'?: string;\n inputValue?: string;\n onInputChange?: (value: string) => void;\n}\n\n/**\n * Generic ComboBox component for searchable single-selection.\n * \n * Uses React Aria Components ComboBox for accessible selection with filtering.\n * Reusable for any data type - countries, users, categories, etc.\n * \n * @example\n * ```tsx\n * const items = [\n * { id: 1, label: 'Apple' },\n * { id: 2, label: 'Banana' },\n * { id: 3, label: 'Orange' },\n * ];\n * \n * <ComboBox\n * label=\"Fruit\"\n * items={items}\n * selectedKey={selectedId}\n * onSelectionChange={setSelectedId}\n * placeholder=\"Select a fruit\"\n * />\n * ```\n */\nexport function ComboBox({\n label,\n description,\n errorMessage,\n isRequired = false,\n isDisabled = false,\n selectedKey,\n onSelectionChange,\n items,\n placeholder,\n 'aria-label': ariaLabel,\n inputValue: controlledInputValue,\n onInputChange: controlledOnInputChange,\n}: ComboBoxProps) {\n return (\n <AriaComboBox\n className={comboBoxContainerStyles}\n inputValue={controlledInputValue}\n onInputChange={controlledOnInputChange}\n selectedKey={selectedKey}\n onSelectionChange={onSelectionChange}\n isDisabled={isDisabled}\n isRequired={isRequired}\n aria-label={ariaLabel || label}\n >\n {label && <Label className={labelStyles}>{label}</Label>}\n <div className={inputWrapperStyles}>\n <Input className={inputStyles} placeholder={placeholder} />\n <Button className={buttonStyles}>\n <ChevronDown />\n </Button>\n </div>\n {description && !errorMessage && (\n <Text slot=\"description\" className={descriptionStyles}>\n {description}\n </Text>\n )}\n {errorMessage && <FieldError className={errorStyles}>{errorMessage}</FieldError>}\n <Popover className={popoverStyles}>\n <ListBox className={listBoxStyles} items={items}>\n {(item) => (\n <ListBoxItem\n key={item.id}\n id={item.id}\n textValue={item.textValue || item.label}\n className={listBoxItemStyles}\n >\n {item.label}\n </ListBoxItem>\n )}\n </ListBox>\n </Popover>\n </AriaComboBox>\n );\n}\n","import {\n Button as AriaButton,\n Disclosure,\n DisclosureGroup as AriaDisclosureGroup,\n DisclosurePanel,\n DisclosureStateContext,\n Heading\n} from 'react-aria-components';\nimport ChevronRight from '@react-spectrum/s2/icons/ChevronRight';\nimport type { DisclosureGroupProps } from 'react-aria-components';\nimport { style, iconStyle, focusRing } from '@react-spectrum/s2/style' with { type: 'macro' };\nimport { useContext } from 'react';\n\nimport './DisclosureGroup.css';\n\n// Disclosure container - very thin grey border, full width button appearance\nconst disclosureContainerStyles = style({\n borderStyle: 'none',\n borderWidth: 0,\n borderColor: 'transparent',\n borderRadius: 'lg',\n overflow: 'hidden',\n width: 'full',\n backgroundColor: '--yogurt-100'\n});\n\n// Disclosure trigger button - blends seamlessly with container\nconst disclosureTriggerStyles = style({\n ...focusRing(),\n font: 'title',\n color: {\n default: '--plum-700',\n isHovered: '--plum-800',\n isFocusVisible: '--plum-800',\n isPressed: '--plum-900'\n },\n display: 'flex',\n alignItems: 'center',\n gap: 8,\n padding: 16,\n paddingX: 20,\n width: 'full',\n backgroundColor: {\n default: '--yogurt-100',\n isHovered: '--yogurt-200',\n isPressed: '--yogurt-300'\n },\n borderStyle: 'none',\n borderRadius: 'none',\n cursor: 'pointer'\n});\n\nconst disclosureHeaderStyles = style({\n margin: 0,\n});\n\n// Disclosure panel - white/light background, blends with button header\nconst disclosurePanelStyles = style({\n padding: {\n default: 0,\n isExpanded: 20,\n },\n backgroundColor: '--yogurt-50',\n borderTopWidth: 1,\n borderTopStyle: 'solid',\n borderColor: '--yogurt-300'\n});\n\nexport interface DisclosureItem {\n id: string;\n title: string;\n content: React.ReactNode;\n onPress?: () => void;\n}\n\ninterface CustomDisclosureGroupProps extends Omit<DisclosureGroupProps, 'children'> {\n items: DisclosureItem[];\n 'aria-label'?: string;\n}\n\n/**\n * Reusable DisclosureGroup component\n * Displays collapsible sections with consistent styling\n * \n * @example\n * <DisclosureGroup\n * items={[\n * {\n * id: 'section1',\n * title: 'Section 1',\n * content: <div>Content goes here</div>\n * }\n * ]}\n * />\n */\nexport function DisclosureGroup({ items, ...props }: CustomDisclosureGroupProps) {\n return (\n <AriaDisclosureGroup {...props} className={disclosureContainerStyles}>\n {items.map((item) => (\n <Disclosure key={item.id}>\n <DisclosureContents key={item.id} {...item} />\n </Disclosure>\n ))}\n </AriaDisclosureGroup>\n );\n}\n\nconst DisclosureContents = (item: DisclosureItem) => {\n let { isExpanded } = useContext(DisclosureStateContext)!;\n\n return (\n <>\n <Heading className={disclosureHeaderStyles}>\n <AriaButton\n slot=\"trigger\"\n className={(renderProps) =>\n `disclosure-chevron ${disclosureTriggerStyles(renderProps)}`\n }\n onPress={item.onPress}\n >\n <ChevronRight styles={iconStyle({ size: 'S' })} />\n {item.title}\n </AriaButton>\n </Heading>\n <DisclosurePanel className={disclosurePanelStyles({ isExpanded })}>\n {item.content}\n </DisclosurePanel>\n </>\n );\n}\n","import {\n TextField as AriaTextField,\n Label,\n Text,\n} from 'react-aria-components';\nimport { style, } from '@react-spectrum/s2/style' with { type: 'macro' };\nimport {\n textFieldDescriptionStyles as labeledValueDescriptionStyles,\n textFieldErrorStyles as labeledValueErrorStyles,\n textFieldLabelStyles as labeledValueLabelStyles,\n} from './TextField';\n\nexport interface LabeledValueProps {\n label: string;\n error?: string;\n description?: string;\n children: React.ReactNode;\n}\n\nconst labeledValueStyles = style({\n display: 'flex',\n flexDirection: 'column',\n gap: 8,\n marginBottom: 20,\n});\n\nconst labeledValueValueStyles = style({\n font: 'body',\n color: '--plum-700',\n});\n\n\nexport function LabeledValue({ label, children, error, description, ...props }: LabeledValueProps) {\n return (\n <AriaTextField className={labeledValueStyles} {...props}>\n <Label className={labeledValueLabelStyles}>{label}</Label>\n <span className={labeledValueValueStyles}>\n {children}\n </span>\n {description && !error && (\n <Text slot=\"description\" className={labeledValueDescriptionStyles}>\n {description}\n </Text>\n )}\n {error && (\n <Text slot=\"errorMessage\" className={labeledValueErrorStyles}>\n {error}\n </Text>\n )}\n </AriaTextField>\n );\n}\n","import { Radio as AriaRadio, RadioGroup as AriaRadioGroup, type RadioGroupProps as AriaRadioGroupProps, type RadioProps as AriaRadioProps } from 'react-aria-components';\nimport { style, focusRing } from '@react-spectrum/s2/style' with { type: 'macro' };\n\nexport interface RadioGroupProps extends Omit<AriaRadioGroupProps, 'children'> {\n label: string;\n options: Array<{ id: string; label: string; value: string }>;\n error?: string;\n}\n\nexport interface RadioProps extends AriaRadioProps {\n children: React.ReactNode;\n}\n\nconst radioGroupStyles = style({\n display: 'flex',\n flexDirection: 'column',\n gap: 8,\n});\n\nconst labelStyles = style({\n font: 'body',\n fontWeight: 'medium',\n color: '--plum-700',\n marginBottom: 8,\n});\n\nconst radioContainerStyles = style({\n display: 'flex',\n flexDirection: 'column',\n gap: 12,\n});\n\nconst radioStyles = style({\n ...focusRing(),\n display: 'flex',\n alignItems: 'center',\n gap: 8,\n font: 'body',\n color: {\n default: '--plum-700',\n isSelected: '--plum-800',\n isHovered: '--plum-600',\n isDisabled: 'gray-400',\n },\n cursor: 'pointer',\n padding: 8,\n borderRadius: 'lg',\n backgroundColor: {\n default: 'transparent',\n isHovered: '--plum-50',\n },\n});\n\nconst radioButtonStyles = style({\n width: 20,\n height: 20,\n borderRadius: 'full',\n borderWidth: 2,\n borderStyle: 'solid',\n borderColor: {\n default: 'gray-400',\n isSelected: '--plum-500',\n isHovered: '--plum-300',\n isDisabled: 'gray-200',\n },\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n flexShrink: 0,\n backgroundColor: {\n default: 'layer-1',\n isDisabled: 'gray-100',\n },\n});\n\nconst radioInnerDotStyles = style({\n width: 10,\n height: 10,\n borderRadius: 'full',\n backgroundColor: '--plum-500',\n opacity: {\n default: 0,\n isSelected: 1,\n },\n});\n\nconst errorStyles = style({\n font: 'body-sm',\n color: '--berry-600',\n marginTop: 4,\n});\n\nexport function Radio({ children, ...props }: RadioProps) {\n return (\n <AriaRadio {...props} className={renderProps => radioStyles(renderProps)}>\n {renderProps => (\n <>\n <div className={radioButtonStyles(renderProps)}>\n <div className={radioInnerDotStyles(renderProps)} />\n </div>\n <span>{children}</span>\n </>\n )}\n </AriaRadio>\n );\n}\n\nexport function RadioGroup({ label, options, error, ...props }: RadioGroupProps) {\n return (\n <AriaRadioGroup {...props} className={radioGroupStyles}>\n <span className={labelStyles}>{label}</span>\n <div className={radioContainerStyles}>\n {options.map(option => (\n <Radio key={option.id} value={option.value}>\n {option.label}\n </Radio>\n ))}\n </div>\n {error && <span className={errorStyles}>{error}</span>}\n </AriaRadioGroup>\n );\n}\n","import { SearchField as AriaSearchField, Input, Label, Button } from 'react-aria-components';\nimport Close from '@react-spectrum/s2/icons/Close';\nimport { focusRing, style } from '@react-spectrum/s2/style' with { type: 'macro' };\nimport { raw } from '../utils/styleMacro' with { type: 'macro' };\nimport Search from '@react-spectrum/s2/icons/Search';\n\n\nconst searchFieldContainerStyles = style({\n flex: {\n default: 'none',\n md: 1,\n },\n});\n\nconst searchFieldStyles = style({\n display: 'flex',\n flexDirection: 'column',\n gap: 4,\n});\n\nconst searchInputContainerStyles = style({\n position: 'relative',\n display: 'flex',\n alignItems: 'center',\n});\n\nconst searchInputStyles = style({\n ...focusRing(),\n width: 'full',\n padding: 8,\n paddingStart: 40,\n font: 'body',\n borderRadius: 'lg',\n borderWidth: 1,\n borderStyle: 'solid',\n borderColor: '--yogurt-400',\n backgroundColor: {\n default: '--yogurt-100',\n isHovered: '--yogurt-200',\n isFocusVisible: '--yogurt-200',\n },\n});\n\nconst labelStyles = style({\n font: 'body',\n color: '--plum-700',\n marginBottom: 4,\n});\n\nconst searchIconStyles = {\n position: 'absolute' as const,\n left: 12,\n top: '50%',\n transform: 'translateY(-50%)',\n pointerEvents: 'none' as const,\n color: '--yogurt-600',\n};\n\nconst clearButtonStyles = style({\n ...focusRing(),\n position: 'absolute',\n right: 8,\n top: '50%',\n transform: 'translateY(-50%)',\n padding: 4,\n backgroundColor: 'transparent',\n borderStyle: 'none',\n borderRadius: 'default',\n cursor: 'pointer',\n color: {\n default: '--yogurt-600',\n isHovered: '--yogurt-700',\n isPressed: '--yogurt-800',\n },\n});\n\nexport interface SearchFieldProps {\n value: string;\n onChange: (value: string) => void;\n label: string;\n placeholder: string;\n ariaLabel: string;\n}\n\n/**\n * Reusable SearchField component using React Aria Components\n * Styled with S2 design tokens and includes search icon\n * \n * @example\n * <SearchField\n * value={searchQuery}\n * onChange={setSearchTerm}\n * label=\"Search\"\n * placeholder=\"Search ferments...\"\n * ariaLabel=\"Search ferments by name or description\"\n * />\n */\nexport function SearchField({\n value,\n onChange,\n label,\n placeholder,\n ariaLabel,\n}: SearchFieldProps) {\n return (\n <div className={searchFieldContainerStyles}>\n <AriaSearchField\n value={value}\n onChange={onChange}\n className={searchFieldStyles}\n aria-label={ariaLabel}\n >\n {({ isEmpty }) => (\n <>\n <Label className={labelStyles}>{label}</Label>\n <div className={searchInputContainerStyles}>\n <div style={searchIconStyles}>\n <Search />\n </div>\n <Input className={(renderProps) => searchInputStyles(renderProps) + ' ' + raw('&::-webkit-search-cancel-button { display: none }', 'custom_layer')} placeholder={placeholder} />\n {!isEmpty && <Button className={clearButtonStyles} aria-label=\"Clear search\">\n <Close />\n </Button>}\n </div>\n </>\n )}\n </AriaSearchField>\n </div>\n );\n}\n","import { useRouter } from 'next/navigation';\nimport {\n ToggleButton,\n ToggleButtonGroup,\n SelectionIndicator\n} from 'react-aria-components';\nimport { focusRing, style } from '@react-spectrum/s2/style' with { type: 'macro' };\nimport { useIntl } from '../lib/i18n-context';\nimport GlobeGrid from '@react-spectrum/s2/icons/GlobeGrid';\nimport ListIcon from '@react-spectrum/s2/icons/ViewList';\n\nconst segmentedControlStyles = style({\n display: 'flex',\n gap: 0,\n padding: 4,\n backgroundColor: '--yogurt-200',\n borderRadius: 'lg',\n borderWidth: 1,\n borderStyle: 'solid',\n borderColor: '--yogurt-400',\n});\n\nconst toggleButtonStyles = style({\n ...focusRing(),\n position: 'relative',\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n gap: 8,\n paddingX: 16,\n paddingY: 8,\n font: 'body',\n color: {\n default: '--plum-700',\n isHovered: '--plum-800',\n isFocusVisible: '--plum-800',\n isPressed: '--plum-900'\n },\n backgroundColor: 'transparent',\n borderStyle: 'none',\n borderRadius: 'default',\n cursor: 'pointer',\n zIndex: 1,\n '--iconPrimary': {\n type: 'color',\n value: {\n default: '--plum-700',\n isHovered: '--plum-800',\n isFocusVisible: '--plum-800',\n isPressed: '--plum-900'\n },\n }\n});\n\nconst selectionIndicatorStyles = style({\n position: 'absolute',\n inset: 0,\n borderRadius: 'default',\n borderWidth: 1,\n borderStyle: 'solid',\n borderColor: 'gray-300',\n boxShadow: 'elevated',\n zIndex: -1,\n color: {\n isDisabled: 'gray-400',\n forcedColors: 'ButtonText'\n },\n backgroundColor: {\n default: '--plum-300',\n isHovered: '--plum-400',\n isFocusVisibile: '--plum-400',\n isPressed: '--plum-400',\n isDisabled: 'gray-100',\n forcedColors: 'ButtonFace'\n },\n});\n\ninterface SegmentedControlProps {\n value: 'map' | 'list';\n}\n\n/**\n * SegmentedControl for Map/List view toggle\n * Uses RAC ToggleButtonGroup for accessible segmented control\n */\nexport function SegmentedControl({ value }: SegmentedControlProps) {\n const intl = useIntl();\n const router = useRouter();\n\n const handleSelectionChange = (newValue: 'map' | 'list') => {\n if (newValue === 'map') {\n router.push('/');\n } else {\n router.push('/ferments');\n }\n };\n\n return (\n <ToggleButtonGroup\n selectionMode=\"single\"\n selectedKeys={new Set([value])}\n disallowEmptySelection\n onSelectionChange={(keys) => {\n const selected = Array.from(keys)[0] as 'map' | 'list';\n handleSelectionChange(selected);\n }}\n aria-label={intl.formatMessage({ id: 'nav.viewToggle.ariaLabel' })}\n className={segmentedControlStyles}\n >\n <ToggleButton\n id=\"map\"\n className={(renderProps) => toggleButtonStyles(renderProps)}\n aria-label={intl.formatMessage({ id: 'nav.map' })}\n >\n {(renderProps) => (\n <>\n <SelectionIndicator className={selectionIndicatorStyles(renderProps)} />\n <GlobeGrid aria-hidden=\"true\" />\n <span>{intl.formatMessage({ id: 'nav.map' })}</span>\n </>\n )}\n </ToggleButton>\n\n <ToggleButton\n id=\"list\"\n className={(renderProps) => toggleButtonStyles(renderProps)}\n aria-label={intl.formatMessage({ id: 'nav.list' })}\n >\n {(renderProps) => (\n <>\n <SelectionIndicator className={selectionIndicatorStyles(renderProps)} />\n <ListIcon aria-hidden=\"true\" />\n <span>{intl.formatMessage({ id: 'nav.list' })}</span>\n </>\n )}\n </ToggleButton>\n </ToggleButtonGroup>\n );\n}\n","import {\n Select as AriaSelect,\n SelectProps,\n Label,\n Button,\n SelectValue,\n Popover,\n ListBox,\n ListBoxItem\n} from 'react-aria-components';\nimport { focusRing, style } from '@react-spectrum/s2/style' with { type: 'macro' };\nimport ChevronDown from '@react-spectrum/s2/icons/ChevronDown';\n\nconst selectContainerStyles = style({\n display: 'flex',\n flexDirection: 'column',\n gap: 4,\n minWidth: 200\n});\n\nconst labelStyles = style({\n font: 'body',\n color: '--plum-700',\n});\n\nconst buttonStyles = style({\n ...focusRing(),\n paddingX: 12,\n paddingY: 8,\n backgroundColor: {\n default: '--yogurt-100',\n isHovered: '--yogurt-200',\n isFocusVisible: '--yogurt-200',\n isPressed: '--yogurt-300'\n },\n borderRadius: 'lg',\n borderWidth: 1,\n borderStyle: 'solid',\n borderColor: '--yogurt-400',\n font: 'body',\n color: {\n default: '--plum-700',\n isHovered: '--plum-800',\n isFocused: '--plum-800',\n isPressed: '--plum-900',\n },\n cursor: 'pointer',\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'space-between',\n gap: 8,\n minWidth: 200\n});\n\nconst popoverStyles = style({\n backgroundColor: '--yogurt-50',\n borderRadius: 'lg',\n borderWidth: 1,\n borderStyle: 'solid',\n borderColor: '--yogurt-400',\n boxShadow: 'elevated',\n marginTop: 4,\n maxHeight: 300,\n overflow: 'auto',\n isolation: 'isolate',\n});\n\nconst listBoxStyles = style({\n padding: 4,\n outline: 'none'\n});\n\nconst listBoxItemStyles = style({\n font: 'body',\n paddingX: 8,\n paddingY: 4,\n borderRadius: 'sm',\n cursor: {\n default: 'pointer',\n isDisabled: 'not-allowed'\n },\n backgroundColor: {\n default: 'transparent',\n isHovered: '--yogurt-200',\n isSelected: '--plum-200',\n isFocused: '--yogurt-200',\n isDisabled: '--yogurt-100'\n },\n color: {\n default: '--plum-700',\n isHovered: '--plum-800',\n isFocused: '--plum-800',\n isPressed: '--plum-900',\n isSelected: '--plum-700',\n isDisabled: 'gray-400'\n },\n outline: 'none'\n});\n\nexport interface SelectOption {\n id: string;\n label: string;\n value: string | null;\n isDisabled?: boolean;\n}\n\ninterface CustomSelectProps extends Omit<SelectProps<SelectOption>, 'children'> {\n label: string;\n options: SelectOption[];\n placeholder?: string;\n}\n\n/**\n * Reusable Select component following RAC pattern\n * Label is inside the Select wrapper for proper a11y\n */\nexport function Select({ label, options, placeholder, ...props }: CustomSelectProps) {\n return (\n <AriaSelect {...props} className={selectContainerStyles}>\n <Label className={labelStyles}>{label}</Label>\n <Button className={buttonStyles}>\n <SelectValue />\n <ChevronDown aria-hidden=\"true\" />\n </Button>\n <Popover className={popoverStyles}>\n <ListBox className={listBoxStyles} items={options}>\n {(item) => (\n <ListBoxItem\n key={item.id}\n id={item.id}\n textValue={item.label}\n isDisabled={item.isDisabled}\n className={listBoxItemStyles}\n >\n {item.label}\n </ListBoxItem>\n )}\n </ListBox>\n </Popover>\n </AriaSelect>\n );\n}\n","import { ReactNode } from 'react';\nimport { style } from '@react-spectrum/s2/style' with { type: 'macro' };\n\nexport interface StatCardProps {\n title: string;\n value: ReactNode;\n description?: string;\n}\n\nconst cardStyles = style({\n backgroundColor: 'layer-1',\n borderRadius: 'xl',\n padding: 24,\n borderWidth: 1,\n borderStyle: 'solid',\n borderColor: '--plum-200',\n display: 'flex',\n flexDirection: 'column',\n gap: 12,\n alignItems: 'center',\n textAlign: 'center'\n});\n\nconst cardTitleStyles = style({\n font: 'title-lg',\n color: '--plum-700',\n margin: 0\n});\n\nconst cardValueStyles = style({\n font: 'heading-2xl',\n color: '--plum-700',\n});\n\nconst cardDescStyles = style({\n font: 'body',\n color: '--plum-700',\n margin: 0\n});\n\n/**\n * StatCard component for displaying dashboard statistics\n * \n * @example\n * <StatCard \n * title=\"Total Sources\"\n * value={42}\n * description=\"Active scraping sources\"\n * />\n * \n * @example\n * // With icon as value\n * <StatCard \n * title=\"System Status\"\n * value={<CheckmarkCircle />}\n * description=\"All systems operational\"\n * />\n */\nexport function StatCard({ title, value, description }: StatCardProps) {\n return (\n <div className={cardStyles}>\n <h3 className={cardTitleStyles}>{title}</h3>\n <div className={cardValueStyles}>{value}</div>\n {description && <p className={cardDescStyles}>{description}</p>}\n </div>\n );\n}\n","import { Switch as AriaSwitch, SwitchProps as AriaSwitchProps } from 'react-aria-components';\nimport { focusRing, style } from '@react-spectrum/s2/style' with { type: 'macro' };\n\n// For props: https://react-spectrum.adobe.com/react-aria/Switch.html#props\n// For styling: https://react-spectrum.adobe.com/react-aria/Switch.html#styling\n\nconst switchContainerStyles = style({\n ...focusRing(),\n display: 'flex',\n alignItems: 'center',\n gap: 8,\n paddingEnd: 2,\n cursor: 'pointer',\n font: 'ui-lg',\n color: {\n default: '--plum-700',\n isHovered: '--plum-800',\n isFocusVisible: '--plum-800',\n isPressed: '--plum-900'\n },\n borderRadius: 'full'\n});\n\nconst switchTrackStyles = style({\n width: 44,\n height: 24,\n borderRadius: 'full',\n padding: 2,\n display: 'flex',\n alignItems: 'center',\n backgroundColor: {\n default: '--yogurt-400',\n isSelected: '--plum-500',\n isDisabled: 'disabled'\n },\n borderStyle: {\n forcedColors: 'solid'\n },\n borderColor: {\n forcedColors: 'ButtonBorder'\n },\n borderWidth: {\n forcedColors: 1\n }\n});\n\nconst switchThumbStyles = style({\n width: 20,\n height: 20,\n borderRadius: 'full',\n backgroundColor: {\n default: 'white',\n forcedColors: 'ButtonText'\n },\n transform: {\n default: 'translateX(0)',\n isSelected: 'translateX(22px)'\n }\n});\n\nexport interface SwitchProps extends Omit<AriaSwitchProps, 'children'> {\n children?: React.ReactNode;\n}\n\nexport const Switch = ({ children, ...props }: SwitchProps) => {\n return (\n <AriaSwitch\n {...props}\n className={renderProps => switchContainerStyles(renderProps)}\n >\n {renderProps => (\n <>\n <div className={switchTrackStyles(renderProps)}>\n <div className={switchThumbStyles(renderProps)} />\n </div>\n {children}\n </>\n )}\n </AriaSwitch>\n );\n};","import { focusRing, style } from '@react-spectrum/s2/style' with { type: 'macro' };\nimport { Tabs as AriaTabs, TabList as AriaTabList, Tab as AriaTab, TabPanel as AriaTabPanel } from 'react-aria-components';\nimport type { TabListProps, TabPanelProps, TabProps, TabsProps } from 'react-aria-components';\n\nconst tabsStyles = style({\n display: 'flex',\n flexDirection: 'column',\n gap: 0\n});\n\nconst tabListStyles = style({\n display: 'flex',\n gap: 4,\n borderBottomWidth: 2,\n borderBottomStyle: 'solid',\n borderBottomColor: '--plum-200',\n marginBottom: 24\n});\n\nconst tabStyles = style({\n ...focusRing(),\n paddingX: 20,\n paddingY: 12,\n font: 'body',\n fontWeight: {\n isSelected: 'bold'\n },\n color: {\n default: '--plum-700',\n isSelected: '--plum-800',\n isHovered: '--plum-800',\n isDisabled: '--plum-300'\n },\n backgroundColor: {\n default: 'transparent',\n isHovered: '--plum-50',\n isSelected: '--plum-100'\n },\n borderWidth: 0,\n borderBottomWidth: 2,\n borderStyle: 'solid',\n borderColor: {\n default: 'transparent',\n isSelected: '--plum-700',\n isHovered: '--plum-300'\n },\n cursor: {\n default: 'pointer',\n isDisabled: 'not-allowed'\n },\n transitionProperty: 'all',\n transitionDuration: '200ms'\n});\n\nconst tabPanelStyles = style({\n paddingY: 0,\n outlineStyle: 'none'\n});\n\nexport function Tabs({ children, ...props }: TabsProps) {\n return (\n <AriaTabs className={tabsStyles} {...props}>\n {children}\n </AriaTabs>\n );\n}\n\nexport function TabList<T extends object>({ children, ...props }: TabListProps<T>) {\n return (\n <AriaTabList className={tabListStyles} {...props}>\n {children}\n </AriaTabList>\n );\n}\n\nexport function Tab({ children, ...props }: TabProps) {\n return (\n <AriaTab className={tabStyles} {...props}>\n {children}\n </AriaTab>\n );\n}\n\nexport function TabPanel({ children, ...props }: TabPanelProps) {\n return (\n <AriaTabPanel className={tabPanelStyles} {...props}>\n {children}\n </AriaTabPanel>\n );\n}\n","import {\n TextArea as AriaTextArea,\n TextField as AriaTextField,\n Label,\n} from 'react-aria-components';\nimport { style } from '@react-spectrum/s2/style' with { type: 'macro' };\nimport { textFieldErrorStyles, textFieldLabelStyles, type TextFieldProps, textFieldStyles } from './TextField';\nimport { textFieldInputStyles } from '../utils/styleUtils' with { type: 'macro' };\nimport { useRef, useEffect } from 'react';\n\nexport interface TextAreaProps extends Omit<TextFieldProps, 'type'> { }\n\nconst textareaStyles = style({\n ...textFieldInputStyles(),\n resize: 'none',\n minHeight: 75, // ~3 lines\n maxHeight: '75vh',\n overflowY: 'auto',\n});\n\nexport function TextArea({ label, error, placeholder, value, ...props }: TextAreaProps) {\n const textareaRef = useRef<HTMLTextAreaElement>(null);\n\n // Auto-grow on value change\n useEffect(() => {\n const textarea = textareaRef.current;\n if (!textarea) return;\n\n // Reset height to recalculate\n textarea.style.height = '75px';\n\n // Set to scrollHeight (content height)\n const newHeight = Math.min(textarea.scrollHeight, window.innerHeight * 0.75);\n textarea.style.height = `${newHeight}px`;\n }, [value]);\n\n return (\n <AriaTextField className={textFieldStyles} {...props} value={value}>\n <Label className={textFieldLabelStyles}>{label}</Label>\n <AriaTextArea\n ref={textareaRef}\n className={textareaStyles}\n placeholder={placeholder}\n />\n {error && <div className={textFieldErrorStyles}>{error}</div>}\n </AriaTextField>\n );\n}\n","/* Checkbox styles for svg checked state */\n\n.checkbox-checkmark {\n width: 70%;\n height: 70%;\n fill: none;\n stroke: white;\n stroke-width: 2;\n stroke-linecap: round;\n stroke-linejoin: round;\n transition: stroke-dashoffset 150ms;\n}\n\n.checkbox-checkmark-path {\n stroke-dasharray: 22;\n stroke-dashoffset: 66;\n transition: stroke-dashoffset 150ms;\n}\n\n.checkbox-checkmark-path.checkbox-checkmark-selected {\n stroke-dashoffset: 44;\n}","/* Progress bar animations and transitions */\n.progress-fill {\n transition: width 200ms ease-in-out;\n}\n\n.progress-fill-indeterminate {\n animation: progress-indeterminate 1.5s cubic-bezier(0.4, 0, 0.6, 1) infinite;\n}\n\n@keyframes progress-indeterminate {\n 0% {\n transform: translateX(-100%);\n }\n\n 100% {\n transform: translateX(350%);\n }\n}","/**\n * HealthCheck Component - Animations Only\n * All other styles are in S2 style macros\n */\n\n/* Chevron icon rotation on expansion */\n.disclosure-chevron[aria-expanded=\"true\"] svg {\n transform: rotate(90deg);\n}\n\n.disclosure-chevron svg {\n transition: transform 200ms;\n}\n\n@keyframes slideDown {\n from {\n opacity: 0;\n transform: translateY(-10px);\n }\n\n to {\n opacity: 1;\n transform: translateY(0);\n }\n}\n\n@keyframes slideUp {\n from {\n opacity: 1;\n transform: translateY(0);\n }\n\n to {\n opacity: 0;\n transform: translateY(-10px);\n }\n}"],"names":[],"version":3,"file":"module.css.map"}
package/dist/module.mjs CHANGED
@@ -233,7 +233,6 @@ const $4aac1ae7c2a46df4$export$353f5b6fc5456de1 = ({ children: children, variant
233
233
 
234
234
 
235
235
 
236
- 'use client';
237
236
  const $f62becf1f473d668$export$298b9ad7287f04ba = " sd12 _ta12 Ue12 qe12 Gz12";
238
237
  const $f62becf1f473d668$export$706e9cce604ae69d = " uk12 uch12 udi12 uea12 ugb12 uhd12 uje12 u2NhKxcl12 uic12 -_6BNtrc-d12 vx12 wb12 xb12 _xa12 _Fb12 _FnuYUwec12 p9PEPsb12";
239
238
  const $f62becf1f473d668$var$inputStyles = function anonymous(props) {
@@ -312,7 +311,6 @@ function $f62becf1f473d668$export$2c73285ae9390cec({ label: label, type: type =
312
311
 
313
312
 
314
313
 
315
- 'use client';
316
314
  const $a6c6e9de70b2177d$var$overlayStyles = " _Pb12 Wr12 _lr12 _Ar12 _zr12 g812 sd12 eb12 _Ca12 _Bb12";
317
315
  const $a6c6e9de70b2177d$var$modalStyles = " gqlRAZb12 oe12 ne12 ke12 je12 _nLeasBb12 Th12 Qh12 Sh12 Rh12 Z9ar6Zb12 ZnA12 ZoQAax0d12 LQAax0d12 _ZBuPDyb12";
318
316
  const $a6c6e9de70b2177d$var$headingStyles = " uk12 uch12 udi12 uea12 ugb12 uhd12 uje12 u2NhKxcl12 uic12 -_6BNtrc-lcY1Ce12 vx12 we12 xe12 _xa12 wX0cczbd12 xX0cczbd12 _xX0cczba12 wezxGHbd12 xezxGHbd12 _xezxGHba12 wfe12 xfe12 _xfa12 wfX0cczbd12 xfX0cczbd12 _xfX0cczba12 wfezxGHbd12 xfezxGHbd12 _xfezxGHba12 _Fd12 _FezxGHba12 _FnuYUweb12 po12 Jy12 Gx12 Iy12 Hy12";
@@ -474,7 +472,6 @@ function $a6c6e9de70b2177d$export$a551a871839880f9({ isOpen: isOpen, onClose: on
474
472
 
475
473
 
476
474
 
477
- 'use client';
478
475
  const $f156c2ac5fd12c51$var$containerStyles = " sd12 _ta12 Ub12 qb12 Za12";
479
476
  const $f156c2ac5fd12c51$var$labelStyles = " uk12 uch12 udi12 uea12 ugb12 uhd12 uje12 u2NhKxcl12 uic12 -_6BNtrc-d12 vx12 wb12 xb12 _xa12 _Fb12 _FnuYUwec12 p9PEPsb12";
480
477
  const $f156c2ac5fd12c51$var$searchFieldStyles = " sd12 _ta12 Ub12 qb12";
@@ -690,7 +687,6 @@ function $f156c2ac5fd12c51$export$2f2b9559550c7bbc({ items: items, selectedKeys:
690
687
 
691
688
 
692
689
 
693
- 'use client';
694
690
  const $35fcc32020885daa$var$checkboxStyles = function anonymous(props) {
695
691
  let rules = " ";
696
692
  rules += ' sd12';
@@ -846,7 +842,6 @@ function $61479464bb5fd0ad$export$c17561cb55d4db30({ label: label, value: value
846
842
 
847
843
 
848
844
 
849
- 'use client';
850
845
  const $8fd64f6a3d6adad1$var$tableContainerStyles = " gqlRAZb12 oe12 ne12 ke12 je12 _kb12 hb12 mb12 lb12 _jf12 i05TOsb12 _Nc12 Pc12";
851
846
  const $8fd64f6a3d6adad1$var$tableStyles = " Za12 __na12";
852
847
  const $8fd64f6a3d6adad1$var$tableHeaderStyles = " gG3O2ub12 hb12";
@@ -1044,7 +1039,6 @@ function $8fd64f6a3d6adad1$export$54ec01a60f47d33d({ data: data, columns: column
1044
1039
  }
1045
1040
 
1046
1041
 
1047
- 'use client';
1048
1042
  const $07375c4c274a5e99$var$containerStyles = " sd12 _ta12 Ul12 ql12 Za12";
1049
1043
  const $07375c4c274a5e99$var$tableContainerStyles = " KlMDJtd12 _Na12 Pa12";
1050
1044
  function $07375c4c274a5e99$export$5f8b5a1eceff31bd({ allItems: allItems, selectedKeys: selectedKeys, onSelectionChange: onSelectionChange, selectionMode: selectionMode = 'multiple', searchLabel: searchLabel, searchPlaceholder: searchPlaceholder, getItemText: getItemText, columns: columns, tableLabel: tableLabel }) {
@@ -1083,7 +1077,6 @@ function $07375c4c274a5e99$export$5f8b5a1eceff31bd({ allItems: allItems, selecte
1083
1077
 
1084
1078
 
1085
1079
 
1086
- 'use client';
1087
1080
  const $e2023e6e190b3690$var$badgeStyles = function anonymous(props) {
1088
1081
  let rules = " ";
1089
1082
  rules += ' Tp12';
@@ -1229,7 +1222,6 @@ const $07aaa6869c77f679$export$de65de8213222d10 = ({ onClose: onClose, ...props
1229
1222
 
1230
1223
 
1231
1224
 
1232
- 'use client';
1233
1225
  const $d6f6f2bb59cbf8cf$var$comboBoxContainerStyles = " sd12 _ta12 Ub12 qb12 Nh12";
1234
1226
  const $d6f6f2bb59cbf8cf$var$labelStyles = " uk12 uch12 udi12 uea12 ugb12 uhd12 uje12 u2NhKxcl12 uic12 -_6BNtrc-d12 vx12 wb12 xb12 _xa12 _Fb12 _FnuYUwec12 p9PEPsb12";
1235
1227
  const $d6f6f2bb59cbf8cf$var$inputWrapperStyles = " _Pc12 sd12 eb12";
@@ -1404,7 +1396,6 @@ function $d6f6f2bb59cbf8cf$export$72b9695b8216309a({ label: label, description:
1404
1396
 
1405
1397
 
1406
1398
 
1407
- 'use client';
1408
1399
  // Disclosure container - very thin grey border, full width button appearance
1409
1400
  const $5ddfe94eba6154eb$var$disclosureContainerStyles = " _je12 _ka12 ha12 ma12 la12 iA12 oc12 nc12 kc12 jc12 _Nc12 Pc12 Za12 g3HF2ub12";
1410
1401
  // Disclosure trigger button - blends seamlessly with container
@@ -1525,7 +1516,6 @@ const $5ddfe94eba6154eb$var$DisclosureContents = (item)=>{
1525
1516
 
1526
1517
 
1527
1518
 
1528
- 'use client';
1529
1519
  const $a7c96df248e47957$var$filterContainerStyles = " sd12 Uh12 qh12 Tp12 Qp12 Sp12 Rp12 gG3O2ub12 oc12 nc12 kc12 jc12 _kb12 hb12 mb12 lb12 _jf12 iWK72ub12";
1530
1520
  const $a7c96df248e47957$var$filterButtonStyles = function anonymous(props) {
1531
1521
  let rules = " ";
@@ -1631,7 +1621,6 @@ function $a7c96df248e47957$export$221f31a87e5a826c({ value: value, onChange: onC
1631
1621
 
1632
1622
 
1633
1623
 
1634
- 'use client';
1635
1624
  const $e6c4d3d9e51c440a$var$labeledValueStyles = " sd12 _ta12 Ue12 qe12 Gz12";
1636
1625
  const $e6c4d3d9e51c440a$var$labeledValueValueStyles = " uk12 uch12 udi12 uea12 ugb12 uhd12 uje12 u2NhKxcl12 uic12 -_6BNtrc-d12 vx12 wb12 xb12 _xa12 _Fb12 _FnuYUwec12 p9PEPsb12";
1637
1626
  function $e6c4d3d9e51c440a$export$d1328f67a56fa517({ label: label, children: children, error: error, description: description, ...props }) {
@@ -1849,7 +1838,6 @@ function $4f3552ad992cebcc$export$a98f0dcb43a68a25({ label: label, options: opti
1849
1838
 
1850
1839
 
1851
1840
 
1852
- 'use client';
1853
1841
  const $9260936bb33ab2d4$var$searchFieldContainerStyles = "";
1854
1842
  const $9260936bb33ab2d4$var$searchFieldStyles = " sd12 _ta12 Ub12 qb12";
1855
1843
  const $9260936bb33ab2d4$var$searchInputContainerStyles = " _Pc12 sd12 eb12";
@@ -1978,7 +1966,6 @@ function $9260936bb33ab2d4$export$b94867ecbd698f21({ value: value, onChange: onC
1978
1966
 
1979
1967
 
1980
1968
 
1981
- 'use client';
1982
1969
  const $dc7b7ce521817383$var$segmentedControlStyles = " sd12 Uh12 qh12 Tp12 Qp12 Sp12 Rp12 gG3O2ub12 oc12 nc12 kc12 jc12 _kb12 hb12 mb12 lb12 _jf12 iWK72ub12";
1983
1970
  const $dc7b7ce521817383$var$toggleButtonStyles = function anonymous(props) {
1984
1971
  let rules = " ";
@@ -2134,7 +2121,6 @@ function $dc7b7ce521817383$export$668709c620d0b8e2({ value: value }) {
2134
2121
 
2135
2122
 
2136
2123
 
2137
- 'use client';
2138
2124
  const $4c94f3494e92f172$var$selectContainerStyles = " sd12 _ta12 Ub12 qb12 Ng12";
2139
2125
  const $4c94f3494e92f172$var$labelStyles = " uk12 uch12 udi12 uea12 ugb12 uhd12 uje12 u2NhKxcl12 uic12 -_6BNtrc-d12 vx12 wb12 xb12 _xa12 _Fb12 _FnuYUwec12 p9PEPsb12";
2140
2126
  const $4c94f3494e92f172$var$buttonStyles = function anonymous(props) {
@@ -2272,7 +2258,6 @@ function $4c94f3494e92f172$export$ef9b1a59e592288f({ label: label, options: opti
2272
2258
 
2273
2259
 
2274
2260
 
2275
- 'use client';
2276
2261
  const $c7af66d6eab82960$var$cardStyles = " gqlRAZb12 oe12 ne12 ke12 je12 Th12 Qh12 Sh12 Rh12 _kb12 hb12 mb12 lb12 _jf12 i05TOsb12 sd12 _ta12 Ug12 qg12 eb12 _Wa12";
2277
2262
  const $c7af66d6eab82960$var$cardTitleStyles = " uk12 uch12 udi12 uea12 ugb12 uhd12 uje12 u2NhKxcl12 uic12 -_6BNtrc-e12 vx12 wd12 xd12 _xa12 wX0cczbc12 xX0cczbc12 _xX0cczba12 wfd12 xfd12 _xfa12 wfX0cczbc12 xfX0cczbc12 _xfX0cczba12 _Fd12 _FezxGHba12 _FnuYUweb12 p9PEPsb12 Jy12 Gy12 Iy12 Hy12";
2278
2263
  const $c7af66d6eab82960$var$cardValueStyles = " uk12 uch12 udi12 uea12 ugb12 uhd12 uje12 u2NhKxcl12 uic12 -_6BNtrc-snabcc12 vx12 we12 xe12 _xa12 wX0cczbd12 xX0cczbd12 _xX0cczba12 wezxGHbd12 xezxGHbd12 _xezxGHba12 wfe12 xfe12 _xfa12 wfX0cczbd12 xfX0cczbd12 _xfX0cczba12 wfezxGHbd12 xfezxGHbd12 _xfezxGHba12 _Fd12 _FezxGHba12 _FnuYUweb12 p9PEPsb12";
@@ -2492,7 +2477,6 @@ function $73303ac6ce50c127$export$3d96ec278d3efce4({ children: children, ...prop
2492
2477
 
2493
2478
 
2494
2479
 
2495
- 'use client';
2496
2480
  const $db470a4073e4639a$var$textareaStyles = function anonymous(props) {
2497
2481
  let rules = " ";
2498
2482
  rules += ' Te12';