@kreativa/ui 0.1.3 → 0.1.5

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
- {"version":3,"sources":["../src/components/Layout.tsx","../src/components/Sidebar.tsx","../src/components/ServiceSwitcher.tsx","../src/components/Button.tsx","../src/components/Input.tsx","../src/components/Card.tsx","../src/components/LoadingSpinner.tsx","../src/components/EmptyState.tsx","../src/components/Modal.tsx","../src/components/FormInput.tsx","../src/components/FormTextarea.tsx","../src/components/FormButtonGroup.tsx","../src/components/Table.tsx","../src/components/DataTable.tsx","../src/components/Select.tsx","../src/components/Tabs.tsx","../src/components/DatePicker.tsx","../src/components/Timer.tsx"],"sourcesContent":["import { ReactNode } from 'react';\n\ninterface LayoutProps {\n children: ReactNode;\n sidebar?: ReactNode;\n}\n\nexport function Layout({ children, sidebar }: LayoutProps) {\n return (\n <div className=\"min-h-screen flex\">\n {sidebar && (\n <aside className=\"w-64 bg-primary-600 text-white flex flex-col\">\n {sidebar}\n </aside>\n )}\n <main className=\"flex-1 overflow-auto bg-cream-50\">\n <div className=\"p-6\">\n {children}\n </div>\n </main>\n </div>\n );\n}\n","import { ReactNode } from 'react';\n\ninterface SidebarProps {\n header?: ReactNode;\n navigation?: ReactNode;\n footer?: ReactNode;\n}\n\nexport function Sidebar({ header, navigation, footer }: SidebarProps) {\n return (\n <>\n {header && (\n <div className=\"p-4 border-b border-primary-500\">\n {header}\n </div>\n )}\n <nav className=\"flex-1 p-4 overflow-y-auto\">\n {navigation}\n </nav>\n {footer && (\n <div className=\"p-4 border-t border-primary-500\">\n {footer}\n </div>\n )}\n </>\n );\n}\n","interface Service {\n id: string;\n name: string;\n icon?: string;\n}\n\ninterface ServiceSwitcherProps {\n services: Service[];\n currentServiceId: string;\n onServiceChange: (serviceId: string) => void;\n}\n\nexport function ServiceSwitcher({ services, currentServiceId, onServiceChange }: ServiceSwitcherProps) {\n if (services.length <= 1) {\n return null;\n }\n\n return (\n <div className=\"mt-2\">\n <select\n value={currentServiceId}\n onChange={(e) => onServiceChange(e.target.value)}\n className=\"w-full px-3 py-2 rounded-lg text-sm appearance-none cursor-pointer bg-primary-500 text-white border border-primary-400 focus:outline-none focus:ring-2 focus:ring-primary-300\"\n >\n {services.map((service) => (\n <option key={service.id} value={service.id}>\n {service.name}\n </option>\n ))}\n </select>\n </div>\n );\n}\n","import { ButtonHTMLAttributes, ReactNode } from 'react';\n\ninterface ButtonProps extends ButtonHTMLAttributes<HTMLButtonElement> {\n variant?: 'primary' | 'secondary' | 'danger' | 'ghost';\n size?: 'sm' | 'md' | 'lg';\n children: ReactNode;\n}\n\nconst variantClasses = {\n primary: 'bg-pink-500 hover:bg-pink-600 text-white',\n secondary: 'bg-primary-500 hover:bg-primary-600 text-white',\n danger: 'bg-red-500 hover:bg-red-600 text-white',\n ghost: 'bg-transparent hover:bg-primary-100 text-primary-600',\n};\n\nconst sizeClasses = {\n sm: 'px-3 py-1.5 text-sm',\n md: 'px-4 py-2 text-base',\n lg: 'px-6 py-3 text-lg',\n};\n\nexport function Button({\n variant = 'primary',\n size = 'md',\n className = '',\n children,\n disabled,\n ...props\n}: ButtonProps) {\n return (\n <button\n className={`\n inline-flex items-center justify-center rounded-lg font-medium\n transition-colors focus:outline-none focus:ring-2 focus:ring-primary-500 focus:ring-offset-2\n disabled:opacity-50 disabled:cursor-not-allowed\n ${variantClasses[variant]}\n ${sizeClasses[size]}\n ${className}\n `}\n disabled={disabled}\n {...props}\n >\n {children}\n </button>\n );\n}\n","import { InputHTMLAttributes, forwardRef } from 'react';\n\ninterface InputProps extends InputHTMLAttributes<HTMLInputElement> {\n label?: string;\n error?: string;\n}\n\nexport const Input = forwardRef<HTMLInputElement, InputProps>(\n ({ label, error, className = '', ...props }, ref) => {\n return (\n <div className=\"w-full\">\n {label && (\n <label className=\"block text-sm font-medium text-gray-700 mb-1\">\n {label}\n </label>\n )}\n <input\n ref={ref}\n className={`\n w-full px-3 py-2 border rounded-lg\n focus:outline-none focus:ring-2 focus:ring-primary-500 focus:border-primary-500\n disabled:bg-gray-100 disabled:cursor-not-allowed\n ${error ? 'border-red-500' : 'border-gray-300'}\n ${className}\n `}\n {...props}\n />\n {error && (\n <p className=\"mt-1 text-sm text-red-500\">{error}</p>\n )}\n </div>\n );\n }\n);\n\nInput.displayName = 'Input';\n","import { ReactNode } from 'react';\n\ninterface CardProps {\n children: ReactNode;\n className?: string;\n padding?: 'none' | 'sm' | 'md' | 'lg';\n}\n\nconst paddingClasses = {\n none: '',\n sm: 'p-3',\n md: 'p-4',\n lg: 'p-6',\n};\n\nexport function Card({ children, className = '', padding = 'md' }: CardProps) {\n return (\n <div\n className={`\n bg-white rounded-lg shadow-sm border border-gray-200\n ${paddingClasses[padding]}\n ${className}\n `}\n >\n {children}\n </div>\n );\n}\n","interface LoadingSpinnerProps {\n size?: 'sm' | 'md' | 'lg';\n fullScreen?: boolean;\n}\n\nconst sizeClasses = {\n sm: 'w-4 h-4',\n md: 'w-8 h-8',\n lg: 'w-12 h-12',\n};\n\nexport function LoadingSpinner({ size = 'md', fullScreen = false }: LoadingSpinnerProps) {\n const spinner = (\n <div\n className={`\n animate-spin rounded-full border-2 border-primary-200 border-t-primary-600\n ${sizeClasses[size]}\n `}\n />\n );\n\n if (fullScreen) {\n return (\n <div className=\"min-h-screen flex items-center justify-center\">\n {spinner}\n </div>\n );\n }\n\n return spinner;\n}\n","import { ReactNode } from 'react';\n\ninterface EmptyStateProps {\n /** Icon to display - should be an SVG element */\n icon?: ReactNode;\n /** Main heading text */\n title: string;\n /** Supporting description text */\n description?: string;\n /** Optional action button or element */\n action?: ReactNode;\n}\n\n/**\n * EmptyState component for displaying \"no items\" UI consistently across the application.\n * Used when a list or collection has no data to display.\n */\nexport function EmptyState({ icon, title, description, action }: EmptyStateProps) {\n return (\n <div className=\"text-center py-16\">\n {icon && (\n <div className=\"w-16 h-16 mx-auto mb-4 rounded-full bg-gray-100 flex items-center justify-center\">\n {icon}\n </div>\n )}\n <h3 className=\"text-lg font-medium text-gray-800 mb-1\">{title}</h3>\n {description && <p className=\"text-gray-500 mb-4\">{description}</p>}\n {action}\n </div>\n );\n}\n","import { ReactNode, useEffect } from 'react';\n\ninterface ModalProps {\n /** Whether the modal is open */\n isOpen: boolean;\n /** Called when the modal should close (clicking backdrop or pressing Escape) */\n onClose: () => void;\n /** Modal title displayed in the header */\n title: string;\n /** Modal content */\n children: ReactNode;\n /** Maximum width of the modal (default: 'md') */\n maxWidth?: 'sm' | 'md' | 'lg' | 'xl' | '2xl';\n}\n\nconst maxWidthClasses = {\n sm: 'max-w-sm',\n md: 'max-w-md',\n lg: 'max-w-lg',\n xl: 'max-w-xl',\n '2xl': 'max-w-2xl',\n};\n\n/**\n * Modal component for displaying content in an overlay dialog.\n * Handles backdrop click and Escape key to close.\n */\nexport function Modal({ isOpen, onClose, title, children, maxWidth = 'xl' }: ModalProps) {\n // Handle Escape key press\n useEffect(() => {\n const handleEscape = (e: KeyboardEvent) => {\n if (e.key === 'Escape') {\n onClose();\n }\n };\n\n if (isOpen) {\n document.addEventListener('keydown', handleEscape);\n // Prevent body scroll when modal is open\n document.body.style.overflow = 'hidden';\n }\n\n return () => {\n document.removeEventListener('keydown', handleEscape);\n document.body.style.overflow = '';\n };\n }, [isOpen, onClose]);\n\n if (!isOpen) return null;\n\n return (\n <div\n className=\"fixed inset-0 bg-black/50 flex items-center justify-center z-50 p-4\"\n onClick={(e) => {\n // Close when clicking backdrop (not modal content)\n if (e.target === e.currentTarget) {\n onClose();\n }\n }}\n >\n <div\n className={`bg-white rounded-2xl shadow-2xl w-full ${maxWidthClasses[maxWidth]} p-6 max-h-[90vh] overflow-y-auto`}\n >\n <h2 className=\"text-xl font-bold text-gray-800 mb-6\">{title}</h2>\n {children}\n </div>\n </div>\n );\n}\n","import { InputHTMLAttributes, forwardRef } from 'react';\n\ninterface FormInputProps extends InputHTMLAttributes<HTMLInputElement> {\n /** Label text displayed above the input */\n label?: string;\n /** Help text displayed below the input */\n helpText?: string;\n /** Error message to display */\n error?: string;\n}\n\n/**\n * FormInput component with consistent styling for form inputs across the application.\n * Supports labels, help text, and error states.\n */\nexport const FormInput = forwardRef<HTMLInputElement, FormInputProps>(\n ({ label, helpText, error, className = '', ...props }, ref) => {\n return (\n <div>\n {label && (\n <label className=\"block text-sm font-medium text-gray-700 mb-2\">\n {label}\n </label>\n )}\n <input\n ref={ref}\n className={`w-full px-4 py-3 rounded-xl border border-gray-200 focus:outline-none focus:ring-2 focus:ring-primary-500 focus:border-transparent ${\n error ? 'border-red-300 focus:ring-red-500' : ''\n } ${className}`}\n {...props}\n />\n {helpText && !error && (\n <p className=\"mt-1 text-xs text-gray-500\">{helpText}</p>\n )}\n {error && (\n <p className=\"mt-1 text-xs text-red-600\">{error}</p>\n )}\n </div>\n );\n }\n);\n\nFormInput.displayName = 'FormInput';\n","import { TextareaHTMLAttributes, forwardRef } from 'react';\n\ninterface FormTextareaProps extends TextareaHTMLAttributes<HTMLTextAreaElement> {\n /** Label text displayed above the textarea */\n label?: string;\n /** Help text displayed below the textarea */\n helpText?: string;\n /** Error message to display */\n error?: string;\n}\n\n/**\n * FormTextarea component with consistent styling for textarea inputs across the application.\n * Supports labels, help text, and error states.\n */\nexport const FormTextarea = forwardRef<HTMLTextAreaElement, FormTextareaProps>(\n ({ label, helpText, error, className = '', ...props }, ref) => {\n return (\n <div>\n {label && (\n <label className=\"block text-sm font-medium text-gray-700 mb-2\">\n {label}\n </label>\n )}\n <textarea\n ref={ref}\n className={`w-full px-4 py-3 rounded-xl border border-gray-200 focus:outline-none focus:ring-2 focus:ring-primary-500 focus:border-transparent resize-y ${\n error ? 'border-red-300 focus:ring-red-500' : ''\n } ${className}`}\n {...props}\n />\n {helpText && !error && (\n <p className=\"mt-1 text-xs text-gray-500\">{helpText}</p>\n )}\n {error && (\n <p className=\"mt-1 text-xs text-red-600\">{error}</p>\n )}\n </div>\n );\n }\n);\n\nFormTextarea.displayName = 'FormTextarea';\n","import { ReactNode } from 'react';\n\ninterface FormButtonGroupProps {\n /** Text for the cancel button */\n cancelText?: string;\n /** Text for the submit button */\n submitText?: string;\n /** Loading text for submit button (when isLoading is true) */\n loadingText?: string;\n /** Whether the form is in a loading state */\n isLoading?: boolean;\n /** Whether the submit button is disabled */\n isDisabled?: boolean;\n /** Called when cancel button is clicked */\n onCancel: () => void;\n /** Called when submit button is clicked (optional, for use outside forms) */\n onSubmit?: () => void;\n /** Custom submit button content (overrides submitText) */\n submitContent?: ReactNode;\n}\n\n/**\n * FormButtonGroup component for consistent Cancel/Submit button pairs in forms.\n * Handles loading states and disabled states.\n */\nexport function FormButtonGroup({\n cancelText = 'Cancel',\n submitText = 'Save',\n loadingText = 'Saving...',\n isLoading = false,\n isDisabled = false,\n onCancel,\n onSubmit,\n submitContent,\n}: FormButtonGroupProps) {\n return (\n <div className=\"flex gap-3 pt-2\">\n <button\n type=\"button\"\n onClick={onCancel}\n className=\"flex-1 py-3 px-4 bg-gray-100 text-gray-700 font-medium rounded-xl hover:bg-gray-200 transition-colors\"\n >\n {cancelText}\n </button>\n <button\n type={onSubmit ? 'button' : 'submit'}\n onClick={onSubmit}\n disabled={isLoading || isDisabled}\n className=\"flex-1 py-3 px-4 bg-primary-600 text-white font-medium rounded-xl hover:bg-primary-700 transition-colors disabled:opacity-50\"\n >\n {submitContent ?? (isLoading ? loadingText : submitText)}\n </button>\n </div>\n );\n}\n","import { useState, useMemo, useRef, useCallback, ReactNode } from 'react'\n\nexport interface TableColumn<T> {\n /** Unique key for the column */\n key: string\n /** Column header text or React element */\n header: ReactNode\n /** Function to render cell content */\n render: (item: T) => ReactNode\n /** Whether this column is sortable */\n sortable?: boolean\n /** Custom sort function */\n sortFn?: (a: T, b: T) => number\n /** Column width (e.g., '200px', '20%') - used as initial/min width */\n width?: string\n /** Minimum column width when resizing */\n minWidth?: number\n /** Text alignment */\n align?: 'left' | 'center' | 'right'\n}\n\ninterface TableProps<T> {\n /** Array of data items to display */\n data: T[]\n /** Column definitions */\n columns: TableColumn<T>[]\n /** Function to get unique key for each row */\n getRowKey: (item: T) => string | number\n /** Called when a row is clicked */\n onRowClick?: (item: T) => void\n /** Whether the table is in a loading state */\n loading?: boolean\n /** Message to show when data is empty */\n emptyMessage?: string\n /** Additional class names for the table container */\n className?: string\n /** Enable manual column resizing (default: false) */\n resizable?: boolean\n /** Use fixed table layout for consistent column widths */\n fixedLayout?: boolean\n}\n\ntype SortDirection = 'asc' | 'desc' | null\n\n/**\n * Table component for displaying tabular data with sorting and optional resizing.\n *\n * Features:\n * - Responsive by default - shrinks with container\n * - Optional column resizing with drag handles\n * - Sortable columns\n * - Loading and empty states\n */\nexport function Table<T>({\n data,\n columns,\n getRowKey,\n onRowClick,\n loading = false,\n emptyMessage = 'No data available',\n className = '',\n resizable = false,\n fixedLayout = false,\n}: TableProps<T>) {\n const [sortKey, setSortKey] = useState<string | null>(null)\n const [sortDirection, setSortDirection] = useState<SortDirection>(null)\n\n // Column widths for resizing (stored as pixels)\n const [columnWidths, setColumnWidths] = useState<Record<string, number>>({})\n const tableRef = useRef<HTMLTableElement>(null)\n const resizingRef = useRef<{\n columnKey: string\n startX: number\n startWidth: number\n } | null>(null)\n\n const handleHeaderClick = (column: TableColumn<T>) => {\n if (!column.sortable) return\n\n if (sortKey === column.key) {\n // Cycle through: asc -> desc -> null\n if (sortDirection === 'asc') {\n setSortDirection('desc')\n } else if (sortDirection === 'desc') {\n setSortKey(null)\n setSortDirection(null)\n }\n } else {\n setSortKey(column.key)\n setSortDirection('asc')\n }\n }\n\n const sortedData = useMemo(() => {\n if (!sortKey || !sortDirection) return data\n\n const column = columns.find((c) => c.key === sortKey)\n if (!column) return data\n\n const sorted = [...data].sort((a, b) => {\n if (column.sortFn) {\n return column.sortFn(a, b)\n }\n // Default string comparison\n const aVal = String(column.render(a) ?? '')\n const bVal = String(column.render(b) ?? '')\n return aVal.localeCompare(bVal)\n })\n\n return sortDirection === 'desc' ? sorted.reverse() : sorted\n }, [data, columns, sortKey, sortDirection])\n\n // Column resize handlers\n const handleResizeStart = useCallback(\n (e: React.MouseEvent, columnKey: string) => {\n e.preventDefault()\n e.stopPropagation()\n\n const headerCell = e.currentTarget.parentElement\n if (!headerCell) return\n\n const startWidth = headerCell.getBoundingClientRect().width\n resizingRef.current = {\n columnKey,\n startX: e.clientX,\n startWidth,\n }\n\n document.addEventListener('mousemove', handleResizeMove)\n document.addEventListener('mouseup', handleResizeEnd)\n document.body.style.cursor = 'col-resize'\n document.body.style.userSelect = 'none'\n },\n []\n )\n\n const handleResizeMove = useCallback((e: MouseEvent) => {\n if (!resizingRef.current) return\n\n const { columnKey, startX, startWidth } = resizingRef.current\n const column = columns.find((c) => c.key === columnKey)\n const minWidth = column?.minWidth ?? 50\n const newWidth = Math.max(minWidth, startWidth + (e.clientX - startX))\n\n setColumnWidths((prev) => ({\n ...prev,\n [columnKey]: newWidth,\n }))\n }, [columns])\n\n const handleResizeEnd = useCallback(() => {\n resizingRef.current = null\n document.removeEventListener('mousemove', handleResizeMove)\n document.removeEventListener('mouseup', handleResizeEnd)\n document.body.style.cursor = ''\n document.body.style.userSelect = ''\n }, [handleResizeMove])\n\n const getSortIcon = (column: TableColumn<T>) => {\n if (!column.sortable) return null\n\n if (sortKey !== column.key) {\n return (\n <svg className=\"w-4 h-4 text-gray-400 shrink-0\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path strokeLinecap=\"round\" strokeLinejoin=\"round\" strokeWidth={2} d=\"M7 16V4m0 0L3 8m4-4l4 4m6 0v12m0 0l4-4m-4 4l-4-4\" />\n </svg>\n )\n }\n\n if (sortDirection === 'asc') {\n return (\n <svg className=\"w-4 h-4 text-primary-600 shrink-0\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path strokeLinecap=\"round\" strokeLinejoin=\"round\" strokeWidth={2} d=\"M5 15l7-7 7 7\" />\n </svg>\n )\n }\n\n return (\n <svg className=\"w-4 h-4 text-primary-600 shrink-0\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path strokeLinecap=\"round\" strokeLinejoin=\"round\" strokeWidth={2} d=\"M19 9l-7 7-7-7\" />\n </svg>\n )\n }\n\n const alignmentClasses = {\n left: 'text-left',\n center: 'text-center',\n right: 'text-right',\n }\n\n const getColumnStyle = (column: TableColumn<T>): React.CSSProperties => {\n // If we have a resized width, use it\n if (columnWidths[column.key]) {\n return { width: columnWidths[column.key], minWidth: columnWidths[column.key] }\n }\n // Otherwise use the column's defined width as a suggestion\n if (column.width) {\n return { width: column.width, minWidth: column.minWidth ?? 50 }\n }\n return { minWidth: column.minWidth ?? 50 }\n }\n\n return (\n <div className={`overflow-x-auto ${className}`}>\n <table\n ref={tableRef}\n className=\"w-full border-collapse\"\n style={{ tableLayout: fixedLayout || resizable ? 'fixed' : 'auto' }}\n >\n <thead>\n <tr className=\"bg-gray-50 border-b border-gray-200\">\n {columns.map((column, index) => (\n <th\n key={column.key}\n className={`\n px-4 py-3 text-sm font-semibold text-gray-700 relative\n ${alignmentClasses[column.align ?? 'left']}\n ${column.sortable ? 'cursor-pointer select-none hover:bg-gray-100' : ''}\n `}\n style={getColumnStyle(column)}\n onClick={() => handleHeaderClick(column)}\n >\n <div\n className={`flex items-center gap-1 overflow-hidden ${\n column.align === 'right'\n ? 'justify-end'\n : column.align === 'center'\n ? 'justify-center'\n : ''\n }`}\n >\n <span className=\"truncate\">{column.header}</span>\n {getSortIcon(column)}\n </div>\n {/* Resize handle */}\n {resizable && index < columns.length - 1 && (\n <div\n className=\"absolute top-0 right-0 w-1 h-full cursor-col-resize bg-transparent hover:bg-primary-300 transition-colors\"\n onMouseDown={(e) => handleResizeStart(e, column.key)}\n onClick={(e) => e.stopPropagation()}\n />\n )}\n </th>\n ))}\n </tr>\n </thead>\n <tbody>\n {loading ? (\n <tr>\n <td colSpan={columns.length} className=\"px-4 py-8 text-center text-gray-500\">\n <div className=\"flex items-center justify-center gap-2\">\n <div className=\"w-5 h-5 border-2 border-primary-200 border-t-primary-600 rounded-full animate-spin\" />\n <span>Loading...</span>\n </div>\n </td>\n </tr>\n ) : sortedData.length === 0 ? (\n <tr>\n <td colSpan={columns.length} className=\"px-4 py-8 text-center text-gray-500\">\n {emptyMessage}\n </td>\n </tr>\n ) : (\n sortedData.map((item) => (\n <tr\n key={getRowKey(item)}\n className={`\n border-b border-gray-100 hover:bg-gray-50 transition-colors\n ${onRowClick ? 'cursor-pointer' : ''}\n `}\n onClick={() => onRowClick?.(item)}\n >\n {columns.map((column) => (\n <td\n key={column.key}\n className={`px-4 py-3 text-sm text-gray-800 overflow-hidden ${alignmentClasses[column.align ?? 'left']}`}\n style={getColumnStyle(column)}\n >\n <div className=\"truncate\">{column.render(item)}</div>\n </td>\n ))}\n </tr>\n ))\n )}\n </tbody>\n </table>\n </div>\n )\n}\n","import { useState, useMemo, useCallback } from 'react'\nimport { Table, TableColumn } from './Table'\nimport { Input } from './Input'\nimport { Select } from './Select'\n\n// ===========================================\n// Types\n// ===========================================\n\nexport type FilterType = 'text' | 'select' | 'multiselect' | 'boolean' | 'date' | 'none'\n\nexport interface FilterOption {\n value: string\n label: string\n}\n\nexport interface DataTableColumn<T> extends Omit<TableColumn<T>, 'sortable' | 'header'> {\n /** Column header text (must be string for filter placeholder) */\n header: string\n /** Whether this column is sortable (default: true) */\n sortable?: boolean\n /** Filter type for this column (default: 'text') */\n filterType?: FilterType\n /** Options for select/multiselect filters */\n filterOptions?: FilterOption[]\n /** Function to get filterable value from item */\n filterValue?: (item: T) => string | number | boolean | null | undefined\n /** Placeholder for filter input */\n filterPlaceholder?: string\n}\n\nexport interface DataTableProps<T> {\n /** Array of data items to display */\n data: T[]\n /** Column definitions */\n columns: DataTableColumn<T>[]\n /** Function to get unique key for each row */\n getRowKey: (item: T) => string | number\n /** Called when a row is clicked */\n onRowClick?: (item: T) => void\n /** Whether the table is in a loading state */\n loading?: boolean\n /** Message to show when data is empty */\n emptyMessage?: string\n /** Additional class names for the table container */\n className?: string\n /** Show filter row (default: true) */\n showFilters?: boolean\n /** Initial sort column key */\n initialSortKey?: string\n /** Initial sort direction */\n initialSortDirection?: 'asc' | 'desc'\n /** Called when filtered data changes (for external use, e.g., showing count) */\n onFilteredDataChange?: (filteredData: T[]) => void\n /** Enable manual column resizing (default: false) */\n resizable?: boolean\n /** Use fixed table layout for consistent column widths */\n fixedLayout?: boolean\n}\n\n// ===========================================\n// Filter Component\n// ===========================================\n\ninterface ColumnFilterProps {\n column: DataTableColumn<unknown>\n value: string | string[]\n onChange: (value: string | string[]) => void\n}\n\nfunction ColumnFilter({ column, value, onChange }: ColumnFilterProps) {\n const filterType = column.filterType ?? 'text'\n\n if (filterType === 'none') {\n return <div className=\"h-9\" />\n }\n\n if (filterType === 'select' && column.filterOptions) {\n return (\n <Select\n options={[{ value: '', label: 'Alla' }, ...column.filterOptions]}\n value={(value as string) || ''}\n onChange={(val) => onChange(val as string)}\n placeholder={column.filterPlaceholder || 'Alla'}\n className=\"w-full text-sm\"\n />\n )\n }\n\n if (filterType === 'multiselect' && column.filterOptions) {\n return (\n <Select\n options={column.filterOptions}\n value={(value as string[]) || []}\n onChange={(val) => onChange(val as string[])}\n placeholder={column.filterPlaceholder || 'Alla'}\n multiple\n className=\"w-full text-sm\"\n />\n )\n }\n\n if (filterType === 'boolean') {\n return (\n <Select\n options={[\n { value: '', label: 'Alla' },\n { value: 'true', label: 'Ja' },\n { value: 'false', label: 'Nej' },\n ]}\n value={(value as string) || ''}\n onChange={(val) => onChange(val as string)}\n className=\"w-full text-sm\"\n />\n )\n }\n\n // Default: text filter\n return (\n <Input\n type=\"text\"\n value={(value as string) || ''}\n onChange={(e) => onChange(e.target.value)}\n placeholder={column.filterPlaceholder || `Filtrera ${column.header.toLowerCase()}...`}\n className=\"w-full text-sm h-9\"\n />\n )\n}\n\n// ===========================================\n// DataTable Component\n// ===========================================\n\n/**\n * DataTable component - an enhanced Table with built-in filtering and sorting.\n *\n * Features:\n * - Text, select, multiselect, and boolean filters per column\n * - Sortable columns (default: all columns are sortable)\n * - Filter state management\n * - Callback when filtered data changes\n *\n * @example\n * ```tsx\n * const columns: DataTableColumn<User>[] = [\n * {\n * key: 'name',\n * header: 'Name',\n * filterType: 'text',\n * filterValue: (user) => user.name,\n * render: (user) => <span>{user.name}</span>,\n * },\n * {\n * key: 'status',\n * header: 'Status',\n * filterType: 'select',\n * filterOptions: [\n * { value: 'active', label: 'Active' },\n * { value: 'inactive', label: 'Inactive' },\n * ],\n * filterValue: (user) => user.status,\n * render: (user) => <Badge>{user.status}</Badge>,\n * },\n * ]\n *\n * <DataTable data={users} columns={columns} getRowKey={(u) => u.id} />\n * ```\n */\nexport function DataTable<T>({\n data,\n columns,\n getRowKey,\n onRowClick,\n loading,\n emptyMessage = 'Ingen data att visa.',\n className,\n showFilters = true,\n initialSortKey,\n initialSortDirection = 'asc',\n onFilteredDataChange,\n resizable = false,\n fixedLayout = false,\n}: DataTableProps<T>) {\n // Filter state: { columnKey: filterValue }\n const [filters, setFilters] = useState<Record<string, string | string[]>>({})\n\n // Sort state\n const [sortKey, setSortKey] = useState<string | null>(initialSortKey || null)\n const [sortDirection, setSortDirection] = useState<'asc' | 'desc'>(initialSortDirection)\n\n // Update filter for a specific column\n const handleFilterChange = useCallback((columnKey: string, value: string | string[]) => {\n setFilters((prev) => {\n const next = { ...prev }\n if (value === '' || (Array.isArray(value) && value.length === 0)) {\n delete next[columnKey]\n } else {\n next[columnKey] = value\n }\n return next\n })\n }, [])\n\n // Clear all filters\n const clearFilters = useCallback(() => {\n setFilters({})\n }, [])\n\n // Apply filtering\n const filteredData = useMemo(() => {\n let result = [...data]\n\n // Apply each filter\n for (const [columnKey, filterValue] of Object.entries(filters)) {\n if (!filterValue || (Array.isArray(filterValue) && filterValue.length === 0)) continue\n\n const column = columns.find((c) => c.key === columnKey)\n if (!column) continue\n\n const getFilterableValue = column.filterValue || ((item: T) => {\n // Default: try to access item[columnKey]\n return (item as Record<string, unknown>)[columnKey]\n })\n\n result = result.filter((item) => {\n const itemValue = getFilterableValue(item)\n\n // Handle null/undefined\n if (itemValue === null || itemValue === undefined) {\n return filterValue === ''\n }\n\n const filterType = column.filterType ?? 'text'\n\n // Boolean filter\n if (filterType === 'boolean') {\n const boolFilterValue = filterValue === 'true'\n return itemValue === boolFilterValue\n }\n\n // Multiselect filter\n if (filterType === 'multiselect' && Array.isArray(filterValue)) {\n return filterValue.includes(String(itemValue))\n }\n\n // Select filter (exact match)\n if (filterType === 'select') {\n return String(itemValue).toLowerCase() === String(filterValue).toLowerCase()\n }\n\n // Text filter (partial match, case insensitive)\n return String(itemValue).toLowerCase().includes(String(filterValue).toLowerCase())\n })\n }\n\n return result\n }, [data, filters, columns])\n\n // Apply sorting\n const sortedData = useMemo(() => {\n if (!sortKey) return filteredData\n\n const column = columns.find((c) => c.key === sortKey)\n if (!column) return filteredData\n\n const sorted = [...filteredData].sort((a, b) => {\n // Use custom sort function if provided\n if (column.sortFn) {\n return column.sortFn(a, b)\n }\n\n // Default sort: use filterValue getter or column key\n const getValueForSort = column.filterValue || ((item: T) => {\n return (item as Record<string, unknown>)[sortKey]\n })\n\n const aVal = getValueForSort(a)\n const bVal = getValueForSort(b)\n\n // Handle null/undefined\n if (aVal === null || aVal === undefined) return 1\n if (bVal === null || bVal === undefined) return -1\n\n // Compare strings\n if (typeof aVal === 'string' && typeof bVal === 'string') {\n return aVal.localeCompare(bVal, 'sv')\n }\n\n // Compare numbers/booleans\n if (aVal < bVal) return -1\n if (aVal > bVal) return 1\n return 0\n })\n\n return sortDirection === 'desc' ? sorted.reverse() : sorted\n }, [filteredData, sortKey, sortDirection, columns])\n\n // Notify parent when filtered data changes\n useMemo(() => {\n onFilteredDataChange?.(sortedData)\n }, [sortedData, onFilteredDataChange])\n\n // Handle column header click for sorting\n const handleSort = useCallback((columnKey: string) => {\n if (sortKey === columnKey) {\n // Toggle direction\n setSortDirection((prev) => (prev === 'asc' ? 'desc' : 'asc'))\n } else {\n // New sort column\n setSortKey(columnKey)\n setSortDirection('asc')\n }\n }, [sortKey])\n\n // Transform columns to include sort click handlers\n const tableColumns = useMemo(() => {\n return columns.map((column) => {\n const isSortable = column.sortable !== false && column.filterType !== 'none'\n const isCurrentSort = sortKey === column.key\n\n return {\n key: column.key,\n header: isSortable ? (\n <button\n onClick={() => handleSort(column.key)}\n className=\"flex items-center gap-1 hover:text-gray-900 transition-colors w-full text-left\"\n >\n {column.header}\n {isCurrentSort ? (\n <span className=\"text-primary-600\">\n {sortDirection === 'asc' ? '↑' : '↓'}\n </span>\n ) : (\n <span className=\"text-gray-400 opacity-50\">↕</span>\n )}\n </button>\n ) : column.header,\n render: column.render,\n width: column.width,\n align: column.align,\n sortable: false, // We handle sorting ourselves\n } as TableColumn<T>\n })\n }, [columns, sortKey, sortDirection, handleSort])\n\n const hasActiveFilters = Object.keys(filters).length > 0\n\n return (\n <div className={className}>\n {/* Filter Row */}\n {showFilters && (\n <div className=\"mb-4\">\n <div className=\"flex flex-wrap items-center gap-2 mb-2\">\n <span className=\"text-sm text-gray-500\">\n Visar {sortedData.length} av {data.length}\n </span>\n {hasActiveFilters && (\n <button\n onClick={clearFilters}\n className=\"text-sm text-primary-600 hover:underline\"\n >\n Rensa filter\n </button>\n )}\n </div>\n {/* Responsive grid: stack on mobile, side-by-side on larger screens */}\n <div className=\"grid grid-cols-1 sm:grid-cols-2 md:grid-cols-3 lg:grid-cols-4 xl:grid-cols-6 gap-3 p-3 bg-gray-50 border border-gray-200 rounded-lg\">\n {columns\n .filter((col) => col.filterType !== 'none')\n .map((column) => (\n <div key={column.key} className=\"min-w-0\">\n <label className=\"text-xs text-gray-500 mb-1 block truncate\">\n {column.header}\n </label>\n <ColumnFilter\n column={column as DataTableColumn<unknown>}\n value={filters[column.key] || ''}\n onChange={(value) => handleFilterChange(column.key, value)}\n />\n </div>\n ))}\n </div>\n </div>\n )}\n\n {/* Table */}\n <Table\n data={sortedData}\n columns={tableColumns}\n getRowKey={getRowKey}\n onRowClick={onRowClick}\n loading={loading}\n emptyMessage={emptyMessage}\n resizable={resizable}\n fixedLayout={fixedLayout}\n />\n </div>\n )\n}\n\n// ===========================================\n// Utility: Create filter options from data\n// ===========================================\n\n/**\n * Create filter options from data array.\n * Extracts unique values and creates option objects.\n *\n * @example\n * ```tsx\n * const statusOptions = createFilterOptions(\n * users,\n * (user) => user.status,\n * { active: 'Active', inactive: 'Inactive' }\n * )\n * ```\n */\nexport function createFilterOptions<T>(\n data: T[],\n getValue: (item: T) => string | null | undefined,\n labelMap?: Record<string, string>\n): FilterOption[] {\n const uniqueValues = new Set<string>()\n\n for (const item of data) {\n const value = getValue(item)\n if (value !== null && value !== undefined && value !== '') {\n uniqueValues.add(value)\n }\n }\n\n return Array.from(uniqueValues)\n .sort((a, b) => a.localeCompare(b, 'sv'))\n .map((value) => ({\n value,\n label: labelMap?.[value] || value,\n }))\n}\n","import { useState, useRef, useEffect, useMemo, ReactNode, KeyboardEvent } from 'react'\n\nexport interface SelectOption<T = string> {\n /** Unique value for the option */\n value: T\n /** Display label */\n label: string\n /** Optional icon or element to display */\n icon?: ReactNode\n /** Whether this option is disabled */\n disabled?: boolean\n}\n\ninterface SelectProps<T = string> {\n /** Available options */\n options: SelectOption<T>[]\n /** Currently selected value(s) */\n value: T | T[] | null\n /** Called when selection changes */\n onChange: (value: T | T[] | null) => void\n /** Placeholder text when nothing selected */\n placeholder?: string\n /** Label text */\n label?: string\n /** Error message */\n error?: string\n /** Whether search is enabled */\n searchable?: boolean\n /** Whether multiple selection is allowed */\n multiple?: boolean\n /** Whether the select is disabled */\n disabled?: boolean\n /** Additional class names */\n className?: string\n}\n\n/**\n * Select component with searchable dropdown and multi-select support.\n */\nexport function Select<T = string>({\n options,\n value,\n onChange,\n placeholder = 'Select...',\n label,\n error,\n searchable = true,\n multiple = false,\n disabled = false,\n className = '',\n}: SelectProps<T>) {\n const [isOpen, setIsOpen] = useState(false)\n const [searchTerm, setSearchTerm] = useState('')\n const [highlightedIndex, setHighlightedIndex] = useState(0)\n const containerRef = useRef<HTMLDivElement>(null)\n const inputRef = useRef<HTMLInputElement>(null)\n\n // Filter options based on search term\n const filteredOptions = useMemo(() => {\n if (!searchTerm) return options\n const term = searchTerm.toLowerCase()\n return options.filter((opt) => opt.label.toLowerCase().includes(term))\n }, [options, searchTerm])\n\n // Get selected options\n const selectedOptions = useMemo(() => {\n if (value === null) return []\n const values = Array.isArray(value) ? value : [value]\n return options.filter((opt) => values.includes(opt.value))\n }, [options, value])\n\n // Display text\n const displayText = useMemo(() => {\n if (selectedOptions.length === 0) return ''\n if (multiple) {\n return selectedOptions.map((opt) => opt.label).join(', ')\n }\n return selectedOptions[0]?.label ?? ''\n }, [selectedOptions, multiple])\n\n // Close on outside click\n useEffect(() => {\n const handleClickOutside = (e: MouseEvent) => {\n if (containerRef.current && !containerRef.current.contains(e.target as Node)) {\n setIsOpen(false)\n setSearchTerm('')\n }\n }\n document.addEventListener('mousedown', handleClickOutside)\n return () => document.removeEventListener('mousedown', handleClickOutside)\n }, [])\n\n // Reset highlighted index when filtered options change\n useEffect(() => {\n setHighlightedIndex(0)\n }, [filteredOptions])\n\n const handleSelect = (option: SelectOption<T>) => {\n if (option.disabled) return\n\n if (multiple) {\n const currentValues = Array.isArray(value) ? value : value ? [value] : []\n const isSelected = currentValues.includes(option.value)\n if (isSelected) {\n const newValues = currentValues.filter((v) => v !== option.value)\n onChange(newValues.length > 0 ? newValues : null)\n } else {\n onChange([...currentValues, option.value])\n }\n } else {\n onChange(option.value)\n setIsOpen(false)\n setSearchTerm('')\n }\n }\n\n const handleKeyDown = (e: KeyboardEvent) => {\n if (disabled) return\n\n switch (e.key) {\n case 'ArrowDown':\n e.preventDefault()\n if (!isOpen) {\n setIsOpen(true)\n } else {\n setHighlightedIndex((prev) => Math.min(prev + 1, filteredOptions.length - 1))\n }\n break\n case 'ArrowUp':\n e.preventDefault()\n setHighlightedIndex((prev) => Math.max(prev - 1, 0))\n break\n case 'Enter':\n e.preventDefault()\n if (isOpen && filteredOptions[highlightedIndex]) {\n handleSelect(filteredOptions[highlightedIndex])\n } else {\n setIsOpen(true)\n }\n break\n case 'Escape':\n setIsOpen(false)\n setSearchTerm('')\n break\n }\n }\n\n const isSelected = (option: SelectOption<T>) => {\n if (value === null) return false\n const values = Array.isArray(value) ? value : [value]\n return values.includes(option.value)\n }\n\n return (\n <div ref={containerRef} className={`relative ${className}`}>\n {label && (\n <label className=\"block text-sm font-medium text-gray-700 mb-2\">{label}</label>\n )}\n\n <div\n className={`\n relative w-full px-4 py-3 rounded-xl border bg-white\n ${disabled ? 'bg-gray-100 cursor-not-allowed' : 'cursor-pointer'}\n ${error ? 'border-red-300' : isOpen ? 'border-primary-500 ring-2 ring-primary-100' : 'border-gray-200'}\n transition-all\n `}\n onClick={() => {\n if (!disabled) {\n setIsOpen(!isOpen)\n if (!isOpen && searchable) {\n setTimeout(() => inputRef.current?.focus(), 0)\n }\n }\n }}\n onKeyDown={handleKeyDown}\n tabIndex={disabled ? -1 : 0}\n >\n <div className=\"flex items-center justify-between\">\n {searchable && isOpen ? (\n <input\n ref={inputRef}\n type=\"text\"\n className=\"w-full outline-none bg-transparent\"\n placeholder={displayText || placeholder}\n value={searchTerm}\n onChange={(e) => setSearchTerm(e.target.value)}\n onClick={(e) => e.stopPropagation()}\n />\n ) : (\n <span className={displayText ? 'text-gray-800' : 'text-gray-400'}>\n {displayText || placeholder}\n </span>\n )}\n <svg\n className={`w-5 h-5 text-gray-400 transition-transform ${isOpen ? 'rotate-180' : ''}`}\n fill=\"none\"\n stroke=\"currentColor\"\n viewBox=\"0 0 24 24\"\n >\n <path strokeLinecap=\"round\" strokeLinejoin=\"round\" strokeWidth={2} d=\"M19 9l-7 7-7-7\" />\n </svg>\n </div>\n </div>\n\n {error && <p className=\"mt-1 text-xs text-red-600\">{error}</p>}\n\n {isOpen && (\n <div className=\"absolute z-50 w-full mt-1 bg-white border border-gray-200 rounded-xl shadow-lg max-h-60 overflow-auto\">\n {filteredOptions.length === 0 ? (\n <div className=\"px-4 py-3 text-sm text-gray-500\">No options found</div>\n ) : (\n filteredOptions.map((option, index) => (\n <div\n key={String(option.value)}\n className={`\n px-4 py-3 text-sm cursor-pointer flex items-center gap-2\n ${option.disabled ? 'text-gray-400 cursor-not-allowed' : 'text-gray-800'}\n ${highlightedIndex === index ? 'bg-primary-50' : 'hover:bg-gray-50'}\n ${isSelected(option) ? 'bg-primary-50 font-medium' : ''}\n `}\n onClick={(e) => {\n e.stopPropagation()\n handleSelect(option)\n }}\n onMouseEnter={() => setHighlightedIndex(index)}\n >\n {multiple && (\n <div\n className={`\n w-4 h-4 border rounded flex items-center justify-center\n ${isSelected(option) ? 'bg-primary-600 border-primary-600' : 'border-gray-300'}\n `}\n >\n {isSelected(option) && (\n <svg className=\"w-3 h-3 text-white\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path strokeLinecap=\"round\" strokeLinejoin=\"round\" strokeWidth={3} d=\"M5 13l4 4L19 7\" />\n </svg>\n )}\n </div>\n )}\n {option.icon}\n <span>{option.label}</span>\n </div>\n ))\n )}\n </div>\n )}\n </div>\n )\n}\n","import { useState, ReactNode, KeyboardEvent } from 'react'\n\nexport interface Tab {\n /** Unique identifier for the tab */\n id: string\n /** Tab label */\n label: string\n /** Optional icon */\n icon?: ReactNode\n /** Whether the tab is disabled */\n disabled?: boolean\n /** Tab content (for uncontrolled mode) */\n content?: ReactNode\n}\n\ninterface TabsProps {\n /** Tab definitions */\n tabs: Tab[]\n /** Currently active tab id (controlled mode) */\n activeTab?: string\n /** Called when tab changes */\n onTabChange?: (tabId: string) => void\n /** Default active tab (uncontrolled mode) */\n defaultTab?: string\n /** Tab variant */\n variant?: 'default' | 'pills' | 'underline'\n /** Whether to render tab content (set to false if rendering content externally) */\n renderContent?: boolean\n /** Additional class names for the tabs container */\n className?: string\n}\n\n/**\n * Tabs component for tab navigation with multiple style variants.\n */\nexport function Tabs({\n tabs,\n activeTab: controlledActiveTab,\n onTabChange,\n defaultTab,\n variant = 'default',\n renderContent = true,\n className = '',\n}: TabsProps) {\n const isControlled = controlledActiveTab !== undefined\n const [internalActiveTab, setInternalActiveTab] = useState(\n defaultTab || tabs.find((t) => !t.disabled)?.id || tabs[0]?.id\n )\n\n const activeTab = isControlled ? controlledActiveTab : internalActiveTab\n\n const handleTabClick = (tab: Tab) => {\n if (tab.disabled) return\n\n if (!isControlled) {\n setInternalActiveTab(tab.id)\n }\n onTabChange?.(tab.id)\n }\n\n const handleKeyDown = (e: KeyboardEvent, index: number) => {\n const enabledTabs = tabs.filter((t) => !t.disabled)\n const currentEnabledIndex = enabledTabs.findIndex((t) => t.id === tabs[index].id)\n\n let newTab: Tab | undefined\n\n switch (e.key) {\n case 'ArrowLeft':\n e.preventDefault()\n newTab = enabledTabs[currentEnabledIndex - 1] || enabledTabs[enabledTabs.length - 1]\n break\n case 'ArrowRight':\n e.preventDefault()\n newTab = enabledTabs[currentEnabledIndex + 1] || enabledTabs[0]\n break\n case 'Home':\n e.preventDefault()\n newTab = enabledTabs[0]\n break\n case 'End':\n e.preventDefault()\n newTab = enabledTabs[enabledTabs.length - 1]\n break\n }\n\n if (newTab) {\n handleTabClick(newTab)\n // Focus the new tab button\n const button = document.querySelector(`[data-tab-id=\"${newTab.id}\"]`) as HTMLElement\n button?.focus()\n }\n }\n\n const activeContent = tabs.find((t) => t.id === activeTab)?.content\n\n // Variant styles\n const variantStyles = {\n default: {\n container: 'border-b border-gray-200',\n tab: (isActive: boolean, isDisabled: boolean) => `\n px-4 py-3 text-sm font-medium border-b-2 -mb-px transition-colors\n ${isDisabled ? 'text-gray-300 cursor-not-allowed' : 'cursor-pointer'}\n ${isActive\n ? 'border-primary-500 text-primary-600'\n : isDisabled\n ? 'border-transparent'\n : 'border-transparent text-gray-500 hover:text-gray-700 hover:border-gray-300'\n }\n `,\n },\n pills: {\n container: 'bg-gray-100 rounded-lg p-1 inline-flex',\n tab: (isActive: boolean, isDisabled: boolean) => `\n px-4 py-2 text-sm font-medium rounded-md transition-colors\n ${isDisabled ? 'text-gray-400 cursor-not-allowed' : 'cursor-pointer'}\n ${isActive\n ? 'bg-white text-gray-900 shadow-sm'\n : isDisabled\n ? ''\n : 'text-gray-500 hover:text-gray-700'\n }\n `,\n },\n underline: {\n container: '',\n tab: (isActive: boolean, isDisabled: boolean) => `\n px-4 py-2 text-sm font-medium transition-colors relative\n ${isDisabled ? 'text-gray-300 cursor-not-allowed' : 'cursor-pointer'}\n ${isActive\n ? 'text-primary-600'\n : isDisabled\n ? ''\n : 'text-gray-500 hover:text-gray-700'\n }\n ${isActive ? 'after:absolute after:bottom-0 after:left-0 after:right-0 after:h-0.5 after:bg-primary-500' : ''}\n `,\n },\n }\n\n const styles = variantStyles[variant]\n\n return (\n <div className={className}>\n {/* Tab list */}\n <div className={`flex ${styles.container}`} role=\"tablist\">\n {tabs.map((tab, index) => {\n const isActive = tab.id === activeTab\n const isDisabled = tab.disabled ?? false\n\n return (\n <button\n key={tab.id}\n type=\"button\"\n role=\"tab\"\n data-tab-id={tab.id}\n aria-selected={isActive}\n aria-disabled={isDisabled}\n tabIndex={isActive ? 0 : -1}\n className={styles.tab(isActive, isDisabled)}\n onClick={() => handleTabClick(tab)}\n onKeyDown={(e) => handleKeyDown(e, index)}\n >\n <span className=\"flex items-center gap-2\">\n {tab.icon}\n {tab.label}\n </span>\n </button>\n )\n })}\n </div>\n\n {/* Tab content */}\n {renderContent && activeContent && (\n <div className=\"pt-4\" role=\"tabpanel\">\n {activeContent}\n </div>\n )}\n </div>\n )\n}\n","import { useState, useRef, useEffect, useMemo } from 'react'\n\nexport interface DateRange {\n start: Date | null\n end: Date | null\n}\n\ninterface DatePickerProps {\n /** Selected date (single mode) or date range (range mode) */\n value: Date | DateRange | null\n /** Called when date selection changes */\n onChange: (value: Date | DateRange | null) => void\n /** Whether to enable range selection */\n range?: boolean\n /** Label text */\n label?: string\n /** Placeholder text */\n placeholder?: string\n /** Error message */\n error?: string\n /** Minimum selectable date */\n minDate?: Date\n /** Maximum selectable date */\n maxDate?: Date\n /** Whether the picker is disabled */\n disabled?: boolean\n /** Additional class names */\n className?: string\n}\n\nconst WEEKDAYS = ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun']\nconst MONTHS = [\n 'January', 'February', 'March', 'April', 'May', 'June',\n 'July', 'August', 'September', 'October', 'November', 'December'\n]\n\ninterface PresetRange {\n label: string\n getValue: () => DateRange\n}\n\nconst PRESET_RANGES: PresetRange[] = [\n {\n label: 'Today',\n getValue: () => {\n const today = new Date()\n today.setHours(0, 0, 0, 0)\n return { start: today, end: today }\n },\n },\n {\n label: 'Yesterday',\n getValue: () => {\n const yesterday = new Date()\n yesterday.setDate(yesterday.getDate() - 1)\n yesterday.setHours(0, 0, 0, 0)\n return { start: yesterday, end: yesterday }\n },\n },\n {\n label: 'Last 7 days',\n getValue: () => {\n const end = new Date()\n end.setHours(0, 0, 0, 0)\n const start = new Date()\n start.setDate(start.getDate() - 6)\n start.setHours(0, 0, 0, 0)\n return { start, end }\n },\n },\n {\n label: 'Last 30 days',\n getValue: () => {\n const end = new Date()\n end.setHours(0, 0, 0, 0)\n const start = new Date()\n start.setDate(start.getDate() - 29)\n start.setHours(0, 0, 0, 0)\n return { start, end }\n },\n },\n {\n label: 'This month',\n getValue: () => {\n const start = new Date()\n start.setDate(1)\n start.setHours(0, 0, 0, 0)\n const end = new Date()\n end.setHours(0, 0, 0, 0)\n return { start, end }\n },\n },\n {\n label: 'Last month',\n getValue: () => {\n const start = new Date()\n start.setMonth(start.getMonth() - 1)\n start.setDate(1)\n start.setHours(0, 0, 0, 0)\n const end = new Date(start.getFullYear(), start.getMonth() + 1, 0)\n end.setHours(0, 0, 0, 0)\n return { start, end }\n },\n },\n]\n\nfunction formatDate(date: Date): string {\n return date.toLocaleDateString('sv-SE') // YYYY-MM-DD format\n}\n\nfunction isSameDay(a: Date, b: Date): boolean {\n return a.getDate() === b.getDate() &&\n a.getMonth() === b.getMonth() &&\n a.getFullYear() === b.getFullYear()\n}\n\nfunction isInRange(date: Date, range: DateRange): boolean {\n if (!range.start || !range.end) return false\n const d = date.getTime()\n return d >= range.start.getTime() && d <= range.end.getTime()\n}\n\n/**\n * DatePicker component with single date and date range support.\n */\nexport function DatePicker({\n value,\n onChange,\n range = false,\n label,\n placeholder = 'Select date',\n error,\n minDate,\n maxDate,\n disabled = false,\n className = '',\n}: DatePickerProps) {\n const [isOpen, setIsOpen] = useState(false)\n const [viewDate, setViewDate] = useState(new Date())\n const [hoverDate, setHoverDate] = useState<Date | null>(null)\n const containerRef = useRef<HTMLDivElement>(null)\n\n // For range selection - track if we're selecting start or end\n const [selectingEnd, setSelectingEnd] = useState(false)\n\n // Close on outside click\n useEffect(() => {\n const handleClickOutside = (e: MouseEvent) => {\n if (containerRef.current && !containerRef.current.contains(e.target as Node)) {\n setIsOpen(false)\n setSelectingEnd(false)\n }\n }\n document.addEventListener('mousedown', handleClickOutside)\n return () => document.removeEventListener('mousedown', handleClickOutside)\n }, [])\n\n // Get display text\n const displayText = useMemo(() => {\n if (!value) return ''\n if (range) {\n const rangeValue = value as DateRange\n if (rangeValue.start && rangeValue.end) {\n if (isSameDay(rangeValue.start, rangeValue.end)) {\n return formatDate(rangeValue.start)\n }\n return `${formatDate(rangeValue.start)} - ${formatDate(rangeValue.end)}`\n }\n if (rangeValue.start) {\n return `${formatDate(rangeValue.start)} - ...`\n }\n return ''\n }\n return formatDate(value as Date)\n }, [value, range])\n\n // Generate calendar days\n const calendarDays = useMemo(() => {\n const year = viewDate.getFullYear()\n const month = viewDate.getMonth()\n const firstDay = new Date(year, month, 1)\n const lastDay = new Date(year, month + 1, 0)\n\n // Get Monday-based day of week (0 = Monday)\n let startDayOfWeek = firstDay.getDay() - 1\n if (startDayOfWeek < 0) startDayOfWeek = 6\n\n const days: (Date | null)[] = []\n\n // Add empty slots for days before the first of the month\n for (let i = 0; i < startDayOfWeek; i++) {\n days.push(null)\n }\n\n // Add all days of the month\n for (let i = 1; i <= lastDay.getDate(); i++) {\n days.push(new Date(year, month, i))\n }\n\n return days\n }, [viewDate])\n\n const handleDateClick = (date: Date) => {\n if (isDateDisabled(date)) return\n\n if (range) {\n const rangeValue = (value as DateRange) || { start: null, end: null }\n\n if (!selectingEnd || !rangeValue.start) {\n // Selecting start date\n onChange({ start: date, end: null })\n setSelectingEnd(true)\n } else {\n // Selecting end date\n if (date < rangeValue.start) {\n // If end is before start, swap them\n onChange({ start: date, end: rangeValue.start })\n } else {\n onChange({ start: rangeValue.start, end: date })\n }\n setSelectingEnd(false)\n setIsOpen(false)\n }\n } else {\n onChange(date)\n setIsOpen(false)\n }\n }\n\n const handlePresetClick = (preset: PresetRange) => {\n const rangeVal = preset.getValue()\n onChange(rangeVal)\n setIsOpen(false)\n setSelectingEnd(false)\n }\n\n const isDateDisabled = (date: Date): boolean => {\n if (minDate && date < minDate) return true\n if (maxDate && date > maxDate) return true\n return false\n }\n\n const isDateSelected = (date: Date): boolean => {\n if (!value) return false\n if (range) {\n const rangeValue = value as DateRange\n if (rangeValue.start && isSameDay(date, rangeValue.start)) return true\n if (rangeValue.end && isSameDay(date, rangeValue.end)) return true\n return false\n }\n return isSameDay(date, value as Date)\n }\n\n const isDateInRange = (date: Date): boolean => {\n if (!range || !value) return false\n const rangeValue = value as DateRange\n\n // If selecting end date and hovering, show preview range\n if (selectingEnd && rangeValue.start && hoverDate) {\n const previewRange: DateRange = {\n start: rangeValue.start,\n end: hoverDate > rangeValue.start ? hoverDate : rangeValue.start,\n }\n if (hoverDate < rangeValue.start) {\n previewRange.start = hoverDate\n previewRange.end = rangeValue.start\n }\n return isInRange(date, previewRange)\n }\n\n if (!rangeValue.start || !rangeValue.end) return false\n return isInRange(date, rangeValue)\n }\n\n const goToPrevMonth = () => {\n setViewDate(new Date(viewDate.getFullYear(), viewDate.getMonth() - 1, 1))\n }\n\n const goToNextMonth = () => {\n setViewDate(new Date(viewDate.getFullYear(), viewDate.getMonth() + 1, 1))\n }\n\n const today = new Date()\n today.setHours(0, 0, 0, 0)\n\n return (\n <div ref={containerRef} className={`relative ${className}`}>\n {label && (\n <label className=\"block text-sm font-medium text-gray-700 mb-2\">{label}</label>\n )}\n\n <div\n className={`\n relative w-full px-4 py-3 rounded-xl border bg-white\n ${disabled ? 'bg-gray-100 cursor-not-allowed' : 'cursor-pointer'}\n ${error ? 'border-red-300' : isOpen ? 'border-primary-500 ring-2 ring-primary-100' : 'border-gray-200'}\n transition-all\n `}\n onClick={() => !disabled && setIsOpen(!isOpen)}\n >\n <div className=\"flex items-center justify-between\">\n <span className={displayText ? 'text-gray-800' : 'text-gray-400'}>\n {displayText || placeholder}\n </span>\n <svg className=\"w-5 h-5 text-gray-400\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path strokeLinecap=\"round\" strokeLinejoin=\"round\" strokeWidth={2} d=\"M8 7V3m8 4V3m-9 8h10M5 21h14a2 2 0 002-2V7a2 2 0 00-2-2H5a2 2 0 00-2 2v12a2 2 0 002 2z\" />\n </svg>\n </div>\n </div>\n\n {error && <p className=\"mt-1 text-xs text-red-600\">{error}</p>}\n\n {isOpen && (\n <div className=\"absolute z-50 mt-1 bg-white border border-gray-200 rounded-xl shadow-lg p-4\">\n <div className={range ? 'flex gap-4' : ''}>\n {/* Preset ranges (only for range mode) */}\n {range && (\n <div className=\"border-r border-gray-100 pr-4 space-y-1\">\n {PRESET_RANGES.map((preset) => (\n <button\n key={preset.label}\n type=\"button\"\n className=\"block w-full text-left px-3 py-2 text-sm text-gray-700 hover:bg-gray-50 rounded-lg\"\n onClick={() => handlePresetClick(preset)}\n >\n {preset.label}\n </button>\n ))}\n </div>\n )}\n\n {/* Calendar */}\n <div>\n {/* Month navigation */}\n <div className=\"flex items-center justify-between mb-4\">\n <button\n type=\"button\"\n className=\"p-1 hover:bg-gray-100 rounded\"\n onClick={goToPrevMonth}\n >\n <svg className=\"w-5 h-5 text-gray-600\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path strokeLinecap=\"round\" strokeLinejoin=\"round\" strokeWidth={2} d=\"M15 19l-7-7 7-7\" />\n </svg>\n </button>\n <span className=\"text-sm font-semibold text-gray-800\">\n {MONTHS[viewDate.getMonth()]} {viewDate.getFullYear()}\n </span>\n <button\n type=\"button\"\n className=\"p-1 hover:bg-gray-100 rounded\"\n onClick={goToNextMonth}\n >\n <svg className=\"w-5 h-5 text-gray-600\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path strokeLinecap=\"round\" strokeLinejoin=\"round\" strokeWidth={2} d=\"M9 5l7 7-7 7\" />\n </svg>\n </button>\n </div>\n\n {/* Weekday headers */}\n <div className=\"grid grid-cols-7 gap-1 mb-2\">\n {WEEKDAYS.map((day) => (\n <div key={day} className=\"text-center text-xs font-medium text-gray-500 py-1\">\n {day}\n </div>\n ))}\n </div>\n\n {/* Calendar days */}\n <div className=\"grid grid-cols-7 gap-1\">\n {calendarDays.map((date, index) => {\n if (!date) {\n return <div key={`empty-${index}`} className=\"w-9 h-9\" />\n }\n\n const isDisabled = isDateDisabled(date)\n const isSelected = isDateSelected(date)\n const inRange = isDateInRange(date)\n const isToday = isSameDay(date, today)\n\n return (\n <button\n key={date.toISOString()}\n type=\"button\"\n className={`\n w-9 h-9 text-sm rounded-lg transition-colors\n ${isDisabled ? 'text-gray-300 cursor-not-allowed' : 'hover:bg-gray-100'}\n ${isSelected ? 'bg-primary-600 text-white hover:bg-primary-700' : ''}\n ${inRange && !isSelected ? 'bg-primary-100' : ''}\n ${isToday && !isSelected ? 'ring-1 ring-primary-400' : ''}\n `}\n onClick={() => handleDateClick(date)}\n onMouseEnter={() => setHoverDate(date)}\n onMouseLeave={() => setHoverDate(null)}\n disabled={isDisabled}\n >\n {date.getDate()}\n </button>\n )\n })}\n </div>\n </div>\n </div>\n </div>\n )}\n </div>\n )\n}\n","import { useState, useEffect, useCallback, useRef } from 'react'\n\nexport interface TimerState {\n /** Whether the timer is currently running */\n isRunning: boolean\n /** Total elapsed time in seconds */\n elapsedSeconds: number\n /** When the timer was started (if running) */\n startedAt: Date | null\n}\n\ninterface TimerProps {\n /** Initial elapsed time in seconds (default: 0) */\n initialSeconds?: number\n /** Called when timer starts */\n onStart?: (startedAt: Date) => void\n /** Called when timer stops */\n onStop?: (elapsedSeconds: number) => void\n /** Called when timer is reset */\n onReset?: () => void\n /** Called every second while running (useful for auto-save) */\n onTick?: (elapsedSeconds: number) => void\n /** Whether to show the reset button */\n showReset?: boolean\n /** Size variant */\n size?: 'sm' | 'md' | 'lg'\n /** Additional class names */\n className?: string\n /** External control - if provided, component becomes controlled */\n isRunning?: boolean\n /** External elapsed seconds - for controlled mode */\n elapsedSeconds?: number\n}\n\nfunction formatTime(totalSeconds: number): string {\n const hours = Math.floor(totalSeconds / 3600)\n const minutes = Math.floor((totalSeconds % 3600) / 60)\n const seconds = totalSeconds % 60\n\n const pad = (n: number) => n.toString().padStart(2, '0')\n\n if (hours > 0) {\n return `${pad(hours)}:${pad(minutes)}:${pad(seconds)}`\n }\n return `${pad(minutes)}:${pad(seconds)}`\n}\n\n/**\n * Timer component for time tracking with play/pause/stop controls.\n */\nexport function Timer({\n initialSeconds = 0,\n onStart,\n onStop,\n onReset,\n onTick,\n showReset = true,\n size = 'md',\n className = '',\n isRunning: controlledIsRunning,\n elapsedSeconds: controlledElapsedSeconds,\n}: TimerProps) {\n // Determine if we're in controlled or uncontrolled mode\n const isControlled = controlledIsRunning !== undefined\n\n const [internalIsRunning, setInternalIsRunning] = useState(false)\n const [internalElapsedSeconds, setInternalElapsedSeconds] = useState(initialSeconds)\n\n const isRunning = isControlled ? controlledIsRunning : internalIsRunning\n const elapsedSeconds = isControlled ? (controlledElapsedSeconds ?? 0) : internalElapsedSeconds\n\n const intervalRef = useRef<ReturnType<typeof setInterval> | null>(null)\n const startTimeRef = useRef<Date | null>(null)\n\n // Clean up interval on unmount\n useEffect(() => {\n return () => {\n if (intervalRef.current) {\n clearInterval(intervalRef.current)\n }\n }\n }, [])\n\n // Handle ticking in uncontrolled mode\n useEffect(() => {\n if (isControlled) return // In controlled mode, parent handles ticking\n\n if (isRunning) {\n intervalRef.current = setInterval(() => {\n setInternalElapsedSeconds((prev) => {\n const newValue = prev + 1\n onTick?.(newValue)\n return newValue\n })\n }, 1000)\n } else {\n if (intervalRef.current) {\n clearInterval(intervalRef.current)\n intervalRef.current = null\n }\n }\n\n return () => {\n if (intervalRef.current) {\n clearInterval(intervalRef.current)\n intervalRef.current = null\n }\n }\n }, [isRunning, isControlled, onTick])\n\n const handleStart = useCallback(() => {\n const now = new Date()\n startTimeRef.current = now\n\n if (!isControlled) {\n setInternalIsRunning(true)\n }\n\n onStart?.(now)\n }, [isControlled, onStart])\n\n const handleStop = useCallback(() => {\n if (!isControlled) {\n setInternalIsRunning(false)\n }\n\n onStop?.(elapsedSeconds)\n }, [isControlled, elapsedSeconds, onStop])\n\n const handleReset = useCallback(() => {\n if (!isControlled) {\n setInternalIsRunning(false)\n setInternalElapsedSeconds(0)\n }\n\n startTimeRef.current = null\n onReset?.()\n }, [isControlled, onReset])\n\n const handleToggle = useCallback(() => {\n if (isRunning) {\n handleStop()\n } else {\n handleStart()\n }\n }, [isRunning, handleStart, handleStop])\n\n // Size variants\n const sizeClasses = {\n sm: {\n container: 'gap-2',\n time: 'text-2xl',\n button: 'w-10 h-10',\n icon: 'w-4 h-4',\n },\n md: {\n container: 'gap-3',\n time: 'text-4xl',\n button: 'w-12 h-12',\n icon: 'w-5 h-5',\n },\n lg: {\n container: 'gap-4',\n time: 'text-5xl',\n button: 'w-14 h-14',\n icon: 'w-6 h-6',\n },\n }\n\n const styles = sizeClasses[size]\n\n return (\n <div className={`flex items-center ${styles.container} ${className}`}>\n {/* Time display */}\n <div className={`font-mono font-bold text-gray-800 ${styles.time} tabular-nums`}>\n {formatTime(elapsedSeconds)}\n </div>\n\n {/* Controls */}\n <div className=\"flex items-center gap-2\">\n {/* Play/Pause button */}\n <button\n type=\"button\"\n onClick={handleToggle}\n className={`\n ${styles.button} rounded-full flex items-center justify-center\n ${isRunning\n ? 'bg-amber-500 hover:bg-amber-600 text-white'\n : 'bg-green-500 hover:bg-green-600 text-white'\n }\n transition-colors focus:outline-none focus:ring-2 focus:ring-offset-2\n ${isRunning ? 'focus:ring-amber-500' : 'focus:ring-green-500'}\n `}\n title={isRunning ? 'Pause' : 'Start'}\n >\n {isRunning ? (\n // Pause icon\n <svg className={styles.icon} fill=\"currentColor\" viewBox=\"0 0 24 24\">\n <path d=\"M6 4h4v16H6V4zm8 0h4v16h-4V4z\" />\n </svg>\n ) : (\n // Play icon\n <svg className={styles.icon} fill=\"currentColor\" viewBox=\"0 0 24 24\">\n <path d=\"M8 5v14l11-7z\" />\n </svg>\n )}\n </button>\n\n {/* Stop button (only visible when timer has time) */}\n {elapsedSeconds > 0 && (\n <button\n type=\"button\"\n onClick={handleStop}\n className={`\n ${styles.button} rounded-full flex items-center justify-center\n bg-red-500 hover:bg-red-600 text-white\n transition-colors focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-red-500\n `}\n title=\"Stop\"\n >\n {/* Stop icon */}\n <svg className={styles.icon} fill=\"currentColor\" viewBox=\"0 0 24 24\">\n <path d=\"M6 6h12v12H6z\" />\n </svg>\n </button>\n )}\n\n {/* Reset button */}\n {showReset && elapsedSeconds > 0 && !isRunning && (\n <button\n type=\"button\"\n onClick={handleReset}\n className={`\n ${styles.button} rounded-full flex items-center justify-center\n bg-gray-200 hover:bg-gray-300 text-gray-700\n transition-colors focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-gray-400\n `}\n title=\"Reset\"\n >\n {/* Reset icon */}\n <svg className={styles.icon} fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path strokeLinecap=\"round\" strokeLinejoin=\"round\" strokeWidth={2} d=\"M4 4v5h.582m15.356 2A8.001 8.001 0 004.582 9m0 0H9m11 11v-5h-.581m0 0a8.003 8.003 0 01-15.357-2m15.357 2H15\" />\n </svg>\n </button>\n )}\n </div>\n </div>\n )\n}\n\n// Export helper function for external use\nexport { formatTime }\n"],"mappings":"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","names":["jsx","jsxs","jsx","jsx","jsx","jsxs","jsx","jsx","sizeClasses","jsx","jsxs","jsx","jsxs","forwardRef","jsx","jsxs","forwardRef","jsx","jsxs","jsx","jsxs","jsx","jsxs","useState","useMemo","useCallback","useState","useRef","useEffect","useMemo","jsx","jsxs","isSelected","jsx","jsxs","useState","useCallback","useMemo","useState","jsx","jsxs","useState","useRef","useEffect","useMemo","jsx","jsxs","useState","useEffect","useCallback","useRef","jsx","jsxs","sizeClasses"]}
1
+ {"version":3,"sources":["../src/components/Layout.tsx","../src/components/Sidebar.tsx","../src/components/ServiceSwitcher.tsx","../src/components/Button.tsx","../src/components/Input.tsx","../src/components/Card.tsx","../src/components/LoadingSpinner.tsx","../src/components/EmptyState.tsx","../src/components/Modal.tsx","../src/components/FormInput.tsx","../src/components/FormTextarea.tsx","../src/components/FormButtonGroup.tsx","../src/components/Table.tsx","../src/components/DataTable.tsx","../src/components/Select.tsx","../src/components/Tabs.tsx","../src/components/DatePicker.tsx","../src/components/Timer.tsx"],"sourcesContent":["import { ReactNode } from 'react';\n\ninterface LayoutProps {\n children: ReactNode;\n sidebar?: ReactNode;\n}\n\nexport function Layout({ children, sidebar }: LayoutProps) {\n return (\n <div className=\"min-h-screen flex\">\n {sidebar && (\n <aside className=\"w-64 bg-primary-600 text-white flex flex-col\">\n {sidebar}\n </aside>\n )}\n <main className=\"flex-1 overflow-auto bg-cream-50\">\n <div className=\"p-6\">\n {children}\n </div>\n </main>\n </div>\n );\n}\n","import { ReactNode } from 'react';\n\ninterface SidebarProps {\n header?: ReactNode;\n navigation?: ReactNode;\n footer?: ReactNode;\n}\n\nexport function Sidebar({ header, navigation, footer }: SidebarProps) {\n return (\n <>\n {header && (\n <div className=\"p-4 border-b border-primary-500\">\n {header}\n </div>\n )}\n <nav className=\"flex-1 p-4 overflow-y-auto\">\n {navigation}\n </nav>\n {footer && (\n <div className=\"p-4 border-t border-primary-500\">\n {footer}\n </div>\n )}\n </>\n );\n}\n","interface Service {\n id: string;\n name: string;\n icon?: string;\n}\n\ninterface ServiceSwitcherProps {\n services: Service[];\n currentServiceId: string;\n onServiceChange: (serviceId: string) => void;\n}\n\nexport function ServiceSwitcher({ services, currentServiceId, onServiceChange }: ServiceSwitcherProps) {\n if (services.length <= 1) {\n return null;\n }\n\n return (\n <div className=\"mt-2\">\n <select\n value={currentServiceId}\n onChange={(e) => onServiceChange(e.target.value)}\n className=\"w-full px-3 py-2 rounded-lg text-sm appearance-none cursor-pointer bg-primary-500 text-white border border-primary-400 focus:outline-none focus:ring-2 focus:ring-primary-300\"\n >\n {services.map((service) => (\n <option key={service.id} value={service.id}>\n {service.name}\n </option>\n ))}\n </select>\n </div>\n );\n}\n","import { ButtonHTMLAttributes, ReactNode } from 'react';\n\ninterface ButtonProps extends ButtonHTMLAttributes<HTMLButtonElement> {\n variant?: 'primary' | 'secondary' | 'danger' | 'ghost';\n size?: 'sm' | 'md' | 'lg';\n children: ReactNode;\n}\n\nconst variantClasses = {\n primary: 'bg-pink-500 hover:bg-pink-600 text-white',\n secondary: 'bg-primary-500 hover:bg-primary-600 text-white',\n danger: 'bg-red-500 hover:bg-red-600 text-white',\n ghost: 'bg-transparent hover:bg-primary-100 text-primary-600',\n};\n\nconst sizeClasses = {\n sm: 'px-3 py-1.5 text-sm',\n md: 'px-4 py-2 text-base',\n lg: 'px-6 py-3 text-lg',\n};\n\nexport function Button({\n variant = 'primary',\n size = 'md',\n className = '',\n children,\n disabled,\n ...props\n}: ButtonProps) {\n return (\n <button\n className={`\n inline-flex items-center justify-center rounded-lg font-medium\n transition-colors focus:outline-none focus:ring-2 focus:ring-primary-500 focus:ring-offset-2\n disabled:opacity-50 disabled:cursor-not-allowed\n ${variantClasses[variant]}\n ${sizeClasses[size]}\n ${className}\n `}\n disabled={disabled}\n {...props}\n >\n {children}\n </button>\n );\n}\n","import { InputHTMLAttributes, forwardRef } from 'react';\n\ninterface InputProps extends InputHTMLAttributes<HTMLInputElement> {\n label?: string;\n error?: string;\n}\n\nexport const Input = forwardRef<HTMLInputElement, InputProps>(\n ({ label, error, className = '', ...props }, ref) => {\n return (\n <div className=\"w-full\">\n {label && (\n <label className=\"block text-sm font-medium text-gray-700 mb-1\">\n {label}\n </label>\n )}\n <input\n ref={ref}\n className={`\n w-full px-3 py-2 border rounded-lg\n focus:outline-none focus:ring-2 focus:ring-primary-500 focus:border-primary-500\n disabled:bg-gray-100 disabled:cursor-not-allowed\n ${error ? 'border-red-500' : 'border-gray-300'}\n ${className}\n `}\n {...props}\n />\n {error && (\n <p className=\"mt-1 text-sm text-red-500\">{error}</p>\n )}\n </div>\n );\n }\n);\n\nInput.displayName = 'Input';\n","import { ReactNode } from 'react';\n\ninterface CardProps {\n children: ReactNode;\n className?: string;\n padding?: 'none' | 'sm' | 'md' | 'lg';\n}\n\nconst paddingClasses = {\n none: '',\n sm: 'p-3',\n md: 'p-4',\n lg: 'p-6',\n};\n\nexport function Card({ children, className = '', padding = 'md' }: CardProps) {\n return (\n <div\n className={`\n bg-white rounded-lg shadow-sm border border-gray-200\n ${paddingClasses[padding]}\n ${className}\n `}\n >\n {children}\n </div>\n );\n}\n","interface LoadingSpinnerProps {\n size?: 'sm' | 'md' | 'lg';\n fullScreen?: boolean;\n}\n\nconst sizeClasses = {\n sm: 'w-4 h-4',\n md: 'w-8 h-8',\n lg: 'w-12 h-12',\n};\n\nexport function LoadingSpinner({ size = 'md', fullScreen = false }: LoadingSpinnerProps) {\n const spinner = (\n <div\n className={`\n animate-spin rounded-full border-2 border-primary-200 border-t-primary-600\n ${sizeClasses[size]}\n `}\n />\n );\n\n if (fullScreen) {\n return (\n <div className=\"min-h-screen flex items-center justify-center\">\n {spinner}\n </div>\n );\n }\n\n return spinner;\n}\n","import { ReactNode } from 'react';\n\ninterface EmptyStateProps {\n /** Icon to display - should be an SVG element */\n icon?: ReactNode;\n /** Main heading text */\n title: string;\n /** Supporting description text */\n description?: string;\n /** Optional action button or element */\n action?: ReactNode;\n}\n\n/**\n * EmptyState component for displaying \"no items\" UI consistently across the application.\n * Used when a list or collection has no data to display.\n */\nexport function EmptyState({ icon, title, description, action }: EmptyStateProps) {\n return (\n <div className=\"text-center py-16\">\n {icon && (\n <div className=\"w-16 h-16 mx-auto mb-4 rounded-full bg-gray-100 flex items-center justify-center\">\n {icon}\n </div>\n )}\n <h3 className=\"text-lg font-medium text-gray-800 mb-1\">{title}</h3>\n {description && <p className=\"text-gray-500 mb-4\">{description}</p>}\n {action}\n </div>\n );\n}\n","import { ReactNode, useEffect, useState } from 'react';\nimport { createPortal } from 'react-dom';\n\ninterface ModalProps {\n /** Whether the modal is open */\n isOpen: boolean;\n /** Called when the modal should close (clicking backdrop or pressing Escape) */\n onClose: () => void;\n /** Modal title displayed in the header */\n title: string;\n /** Modal content */\n children: ReactNode;\n /** Maximum width of the modal (default: 'md') */\n maxWidth?: 'sm' | 'md' | 'lg' | 'xl' | '2xl';\n}\n\nconst maxWidthClasses = {\n sm: 'max-w-sm',\n md: 'max-w-md',\n lg: 'max-w-lg',\n xl: 'max-w-xl',\n '2xl': 'max-w-2xl',\n};\n\n/**\n * Modal component for displaying content in an overlay dialog.\n * Handles backdrop click and Escape key to close.\n * Uses a portal to render at document body level for proper overlay positioning.\n */\nexport function Modal({ isOpen, onClose, title, children, maxWidth = 'xl' }: ModalProps) {\n const [mounted, setMounted] = useState(false);\n\n // Ensure we're on the client before using portals\n useEffect(() => {\n setMounted(true);\n }, []);\n\n // Handle Escape key press\n useEffect(() => {\n const handleEscape = (e: KeyboardEvent) => {\n if (e.key === 'Escape') {\n onClose();\n }\n };\n\n if (isOpen) {\n document.addEventListener('keydown', handleEscape);\n // Prevent body scroll when modal is open\n document.body.style.overflow = 'hidden';\n }\n\n return () => {\n document.removeEventListener('keydown', handleEscape);\n document.body.style.overflow = '';\n };\n }, [isOpen, onClose]);\n\n if (!isOpen || !mounted) return null;\n\n const modalContent = (\n <div\n className=\"fixed inset-0 bg-black/50 flex items-center justify-center z-50 p-4\"\n onClick={(e) => {\n // Close when clicking backdrop (not modal content)\n if (e.target === e.currentTarget) {\n onClose();\n }\n }}\n >\n <div\n className={`bg-white rounded-2xl shadow-2xl w-full ${maxWidthClasses[maxWidth]} p-6 max-h-[90vh] overflow-y-auto`}\n >\n <h2 className=\"text-xl font-bold text-gray-800 mb-6\">{title}</h2>\n {children}\n </div>\n </div>\n );\n\n // Use portal to render at document body level\n return createPortal(modalContent, document.body);\n}\n","import { InputHTMLAttributes, forwardRef } from 'react';\n\ninterface FormInputProps extends InputHTMLAttributes<HTMLInputElement> {\n /** Label text displayed above the input */\n label?: string;\n /** Help text displayed below the input */\n helpText?: string;\n /** Error message to display */\n error?: string;\n}\n\n/**\n * FormInput component with consistent styling for form inputs across the application.\n * Supports labels, help text, and error states.\n */\nexport const FormInput = forwardRef<HTMLInputElement, FormInputProps>(\n ({ label, helpText, error, className = '', ...props }, ref) => {\n return (\n <div>\n {label && (\n <label className=\"block text-sm font-medium text-gray-700 mb-2\">\n {label}\n </label>\n )}\n <input\n ref={ref}\n className={`w-full px-4 py-3 rounded-xl border border-gray-200 focus:outline-none focus:ring-2 focus:ring-primary-500 focus:border-transparent ${\n error ? 'border-red-300 focus:ring-red-500' : ''\n } ${className}`}\n {...props}\n />\n {helpText && !error && (\n <p className=\"mt-1 text-xs text-gray-500\">{helpText}</p>\n )}\n {error && (\n <p className=\"mt-1 text-xs text-red-600\">{error}</p>\n )}\n </div>\n );\n }\n);\n\nFormInput.displayName = 'FormInput';\n","import { TextareaHTMLAttributes, forwardRef } from 'react';\n\ninterface FormTextareaProps extends TextareaHTMLAttributes<HTMLTextAreaElement> {\n /** Label text displayed above the textarea */\n label?: string;\n /** Help text displayed below the textarea */\n helpText?: string;\n /** Error message to display */\n error?: string;\n}\n\n/**\n * FormTextarea component with consistent styling for textarea inputs across the application.\n * Supports labels, help text, and error states.\n */\nexport const FormTextarea = forwardRef<HTMLTextAreaElement, FormTextareaProps>(\n ({ label, helpText, error, className = '', ...props }, ref) => {\n return (\n <div>\n {label && (\n <label className=\"block text-sm font-medium text-gray-700 mb-2\">\n {label}\n </label>\n )}\n <textarea\n ref={ref}\n className={`w-full px-4 py-3 rounded-xl border border-gray-200 focus:outline-none focus:ring-2 focus:ring-primary-500 focus:border-transparent resize-y ${\n error ? 'border-red-300 focus:ring-red-500' : ''\n } ${className}`}\n {...props}\n />\n {helpText && !error && (\n <p className=\"mt-1 text-xs text-gray-500\">{helpText}</p>\n )}\n {error && (\n <p className=\"mt-1 text-xs text-red-600\">{error}</p>\n )}\n </div>\n );\n }\n);\n\nFormTextarea.displayName = 'FormTextarea';\n","import { ReactNode } from 'react';\n\ninterface FormButtonGroupProps {\n /** Text for the cancel button */\n cancelText?: string;\n /** Text for the submit button */\n submitText?: string;\n /** Loading text for submit button (when isLoading is true) */\n loadingText?: string;\n /** Whether the form is in a loading state */\n isLoading?: boolean;\n /** Whether the submit button is disabled */\n isDisabled?: boolean;\n /** Called when cancel button is clicked */\n onCancel: () => void;\n /** Called when submit button is clicked (optional, for use outside forms) */\n onSubmit?: () => void;\n /** Custom submit button content (overrides submitText) */\n submitContent?: ReactNode;\n}\n\n/**\n * FormButtonGroup component for consistent Cancel/Submit button pairs in forms.\n * Handles loading states and disabled states.\n */\nexport function FormButtonGroup({\n cancelText = 'Cancel',\n submitText = 'Save',\n loadingText = 'Saving...',\n isLoading = false,\n isDisabled = false,\n onCancel,\n onSubmit,\n submitContent,\n}: FormButtonGroupProps) {\n return (\n <div className=\"flex gap-3 pt-2\">\n <button\n type=\"button\"\n onClick={onCancel}\n className=\"flex-1 py-3 px-4 bg-gray-100 text-gray-700 font-medium rounded-xl hover:bg-gray-200 transition-colors\"\n >\n {cancelText}\n </button>\n <button\n type={onSubmit ? 'button' : 'submit'}\n onClick={onSubmit}\n disabled={isLoading || isDisabled}\n className=\"flex-1 py-3 px-4 bg-primary-600 text-white font-medium rounded-xl hover:bg-primary-700 transition-colors disabled:opacity-50\"\n >\n {submitContent ?? (isLoading ? loadingText : submitText)}\n </button>\n </div>\n );\n}\n","import { useState, useMemo, useRef, useCallback, ReactNode } from 'react'\n\nexport interface TableColumn<T> {\n /** Unique key for the column */\n key: string\n /** Column header text or React element */\n header: ReactNode\n /** Function to render cell content */\n render: (item: T) => ReactNode\n /** Whether this column is sortable */\n sortable?: boolean\n /** Custom sort function */\n sortFn?: (a: T, b: T) => number\n /** Column width (e.g., '200px', '20%') - used as initial/min width */\n width?: string\n /** Minimum column width when resizing */\n minWidth?: number\n /** Text alignment */\n align?: 'left' | 'center' | 'right'\n}\n\ninterface TableProps<T> {\n /** Array of data items to display */\n data: T[]\n /** Column definitions */\n columns: TableColumn<T>[]\n /** Function to get unique key for each row */\n getRowKey: (item: T) => string | number\n /** Called when a row is clicked */\n onRowClick?: (item: T) => void\n /** Whether the table is in a loading state */\n loading?: boolean\n /** Message to show when data is empty */\n emptyMessage?: string\n /** Additional class names for the table container */\n className?: string\n /** Enable manual column resizing (default: false) */\n resizable?: boolean\n /** Use fixed table layout for consistent column widths */\n fixedLayout?: boolean\n}\n\ntype SortDirection = 'asc' | 'desc' | null\n\n/**\n * Table component for displaying tabular data with sorting and optional resizing.\n *\n * Features:\n * - Responsive by default - shrinks with container\n * - Optional column resizing with drag handles\n * - Sortable columns\n * - Loading and empty states\n */\nexport function Table<T>({\n data,\n columns,\n getRowKey,\n onRowClick,\n loading = false,\n emptyMessage = 'No data available',\n className = '',\n resizable = false,\n fixedLayout = false,\n}: TableProps<T>) {\n const [sortKey, setSortKey] = useState<string | null>(null)\n const [sortDirection, setSortDirection] = useState<SortDirection>(null)\n\n // Column widths for resizing (stored as pixels)\n const [columnWidths, setColumnWidths] = useState<Record<string, number>>({})\n const tableRef = useRef<HTMLTableElement>(null)\n const resizingRef = useRef<{\n columnKey: string\n startX: number\n startWidth: number\n } | null>(null)\n\n const handleHeaderClick = (column: TableColumn<T>) => {\n if (!column.sortable) return\n\n if (sortKey === column.key) {\n // Cycle through: asc -> desc -> null\n if (sortDirection === 'asc') {\n setSortDirection('desc')\n } else if (sortDirection === 'desc') {\n setSortKey(null)\n setSortDirection(null)\n }\n } else {\n setSortKey(column.key)\n setSortDirection('asc')\n }\n }\n\n const sortedData = useMemo(() => {\n if (!sortKey || !sortDirection) return data\n\n const column = columns.find((c) => c.key === sortKey)\n if (!column) return data\n\n const sorted = [...data].sort((a, b) => {\n if (column.sortFn) {\n return column.sortFn(a, b)\n }\n // Default string comparison\n const aVal = String(column.render(a) ?? '')\n const bVal = String(column.render(b) ?? '')\n return aVal.localeCompare(bVal)\n })\n\n return sortDirection === 'desc' ? sorted.reverse() : sorted\n }, [data, columns, sortKey, sortDirection])\n\n // Column resize handlers\n const handleResizeStart = useCallback(\n (e: React.MouseEvent, columnKey: string) => {\n e.preventDefault()\n e.stopPropagation()\n\n const headerCell = e.currentTarget.parentElement\n if (!headerCell) return\n\n const startWidth = headerCell.getBoundingClientRect().width\n resizingRef.current = {\n columnKey,\n startX: e.clientX,\n startWidth,\n }\n\n document.addEventListener('mousemove', handleResizeMove)\n document.addEventListener('mouseup', handleResizeEnd)\n document.body.style.cursor = 'col-resize'\n document.body.style.userSelect = 'none'\n },\n []\n )\n\n const handleResizeMove = useCallback((e: MouseEvent) => {\n if (!resizingRef.current) return\n\n const { columnKey, startX, startWidth } = resizingRef.current\n const column = columns.find((c) => c.key === columnKey)\n const minWidth = column?.minWidth ?? 50\n const newWidth = Math.max(minWidth, startWidth + (e.clientX - startX))\n\n setColumnWidths((prev) => ({\n ...prev,\n [columnKey]: newWidth,\n }))\n }, [columns])\n\n const handleResizeEnd = useCallback(() => {\n resizingRef.current = null\n document.removeEventListener('mousemove', handleResizeMove)\n document.removeEventListener('mouseup', handleResizeEnd)\n document.body.style.cursor = ''\n document.body.style.userSelect = ''\n }, [handleResizeMove])\n\n const getSortIcon = (column: TableColumn<T>) => {\n if (!column.sortable) return null\n\n if (sortKey !== column.key) {\n return (\n <svg className=\"w-4 h-4 text-gray-400 shrink-0\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path strokeLinecap=\"round\" strokeLinejoin=\"round\" strokeWidth={2} d=\"M7 16V4m0 0L3 8m4-4l4 4m6 0v12m0 0l4-4m-4 4l-4-4\" />\n </svg>\n )\n }\n\n if (sortDirection === 'asc') {\n return (\n <svg className=\"w-4 h-4 text-primary-600 shrink-0\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path strokeLinecap=\"round\" strokeLinejoin=\"round\" strokeWidth={2} d=\"M5 15l7-7 7 7\" />\n </svg>\n )\n }\n\n return (\n <svg className=\"w-4 h-4 text-primary-600 shrink-0\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path strokeLinecap=\"round\" strokeLinejoin=\"round\" strokeWidth={2} d=\"M19 9l-7 7-7-7\" />\n </svg>\n )\n }\n\n const alignmentClasses = {\n left: 'text-left',\n center: 'text-center',\n right: 'text-right',\n }\n\n const getColumnStyle = (column: TableColumn<T>): React.CSSProperties => {\n // If we have a resized width, use it\n if (columnWidths[column.key]) {\n return { width: columnWidths[column.key], minWidth: columnWidths[column.key] }\n }\n // Otherwise use the column's defined width as a suggestion\n if (column.width) {\n return { width: column.width, minWidth: column.minWidth ?? 50 }\n }\n return { minWidth: column.minWidth ?? 50 }\n }\n\n return (\n <div className={`overflow-x-auto ${className}`}>\n <table\n ref={tableRef}\n className=\"w-full border-collapse\"\n style={{ tableLayout: fixedLayout || resizable ? 'fixed' : 'auto' }}\n >\n <thead>\n <tr className=\"bg-gray-50 border-b border-gray-200\">\n {columns.map((column, index) => (\n <th\n key={column.key}\n className={`\n px-4 py-3 text-sm font-semibold text-gray-700 relative\n ${alignmentClasses[column.align ?? 'left']}\n ${column.sortable ? 'cursor-pointer select-none hover:bg-gray-100' : ''}\n `}\n style={getColumnStyle(column)}\n onClick={() => handleHeaderClick(column)}\n >\n <div\n className={`flex items-center gap-1 overflow-hidden ${\n column.align === 'right'\n ? 'justify-end'\n : column.align === 'center'\n ? 'justify-center'\n : ''\n }`}\n >\n <span className=\"truncate\">{column.header}</span>\n {getSortIcon(column)}\n </div>\n {/* Resize handle */}\n {resizable && index < columns.length - 1 && (\n <div\n className=\"absolute top-0 right-0 w-1 h-full cursor-col-resize bg-transparent hover:bg-primary-300 transition-colors\"\n onMouseDown={(e) => handleResizeStart(e, column.key)}\n onClick={(e) => e.stopPropagation()}\n />\n )}\n </th>\n ))}\n </tr>\n </thead>\n <tbody>\n {loading ? (\n <tr>\n <td colSpan={columns.length} className=\"px-4 py-8 text-center text-gray-500\">\n <div className=\"flex items-center justify-center gap-2\">\n <div className=\"w-5 h-5 border-2 border-primary-200 border-t-primary-600 rounded-full animate-spin\" />\n <span>Loading...</span>\n </div>\n </td>\n </tr>\n ) : sortedData.length === 0 ? (\n <tr>\n <td colSpan={columns.length} className=\"px-4 py-8 text-center text-gray-500\">\n {emptyMessage}\n </td>\n </tr>\n ) : (\n sortedData.map((item) => (\n <tr\n key={getRowKey(item)}\n className={`\n border-b border-gray-100 hover:bg-gray-50 transition-colors\n ${onRowClick ? 'cursor-pointer' : ''}\n `}\n onClick={() => onRowClick?.(item)}\n >\n {columns.map((column) => (\n <td\n key={column.key}\n className={`px-4 py-3 text-sm text-gray-800 overflow-hidden ${alignmentClasses[column.align ?? 'left']}`}\n style={getColumnStyle(column)}\n >\n <div className=\"truncate\">{column.render(item)}</div>\n </td>\n ))}\n </tr>\n ))\n )}\n </tbody>\n </table>\n </div>\n )\n}\n","import { useState, useMemo, useCallback, useEffect } from 'react'\nimport { Table, TableColumn } from './Table'\nimport { Input } from './Input'\nimport { Select } from './Select'\n\n// ===========================================\n// Types\n// ===========================================\n\nexport type FilterType = 'text' | 'select' | 'multiselect' | 'boolean' | 'date' | 'none'\n\nexport interface FilterOption {\n value: string\n label: string\n}\n\nexport interface DataTableColumn<T> extends Omit<TableColumn<T>, 'sortable' | 'header'> {\n /** Column header text (must be string for filter placeholder) */\n header: string\n /** Whether this column is sortable (default: true) */\n sortable?: boolean\n /** Filter type for this column (default: 'text') */\n filterType?: FilterType\n /** Options for select/multiselect filters */\n filterOptions?: FilterOption[]\n /** Function to get filterable value from item */\n filterValue?: (item: T) => string | number | boolean | null | undefined\n /** Placeholder for filter input */\n filterPlaceholder?: string\n}\n\nexport interface DataTableProps<T> {\n /** Array of data items to display */\n data: T[]\n /** Column definitions */\n columns: DataTableColumn<T>[]\n /** Function to get unique key for each row */\n getRowKey: (item: T) => string | number\n /** Called when a row is clicked */\n onRowClick?: (item: T) => void\n /** Whether the table is in a loading state */\n loading?: boolean\n /** Message to show when data is empty */\n emptyMessage?: string\n /** Additional class names for the table container */\n className?: string\n /** Show filter row (default: true) */\n showFilters?: boolean\n /** Initial sort column key */\n initialSortKey?: string\n /** Initial sort direction */\n initialSortDirection?: 'asc' | 'desc'\n /** Called when filtered data changes (for external use, e.g., showing count) */\n onFilteredDataChange?: (filteredData: T[]) => void\n /** Enable manual column resizing (default: false) */\n resizable?: boolean\n /** Use fixed table layout for consistent column widths */\n fixedLayout?: boolean\n}\n\n// ===========================================\n// Filter Component\n// ===========================================\n\ninterface ColumnFilterProps {\n column: DataTableColumn<unknown>\n value: string | string[]\n onChange: (value: string | string[]) => void\n}\n\nfunction ColumnFilter({ column, value, onChange }: ColumnFilterProps) {\n const filterType = column.filterType ?? 'text'\n\n if (filterType === 'none') {\n return <div className=\"h-9\" />\n }\n\n if (filterType === 'select' && column.filterOptions) {\n return (\n <Select\n options={[{ value: '', label: 'Alla' }, ...column.filterOptions]}\n value={(value as string) || ''}\n onChange={(val) => onChange(val as string)}\n placeholder={column.filterPlaceholder || 'Alla'}\n className=\"w-full text-sm\"\n />\n )\n }\n\n if (filterType === 'multiselect' && column.filterOptions) {\n return (\n <Select\n options={column.filterOptions}\n value={(value as string[]) || []}\n onChange={(val) => onChange(val as string[])}\n placeholder={column.filterPlaceholder || 'Alla'}\n multiple\n className=\"w-full text-sm\"\n />\n )\n }\n\n if (filterType === 'boolean') {\n return (\n <Select\n options={[\n { value: '', label: 'Alla' },\n { value: 'true', label: 'Ja' },\n { value: 'false', label: 'Nej' },\n ]}\n value={(value as string) || ''}\n onChange={(val) => onChange(val as string)}\n className=\"w-full text-sm\"\n />\n )\n }\n\n // Default: text filter\n return (\n <Input\n type=\"text\"\n value={(value as string) || ''}\n onChange={(e) => onChange(e.target.value)}\n placeholder={column.filterPlaceholder || `Filtrera ${column.header.toLowerCase()}...`}\n className=\"w-full text-sm h-9\"\n />\n )\n}\n\n// ===========================================\n// DataTable Component\n// ===========================================\n\n/**\n * DataTable component - an enhanced Table with built-in filtering and sorting.\n *\n * Features:\n * - Text, select, multiselect, and boolean filters per column\n * - Sortable columns (default: all columns are sortable)\n * - Filter state management\n * - Callback when filtered data changes\n *\n * @example\n * ```tsx\n * const columns: DataTableColumn<User>[] = [\n * {\n * key: 'name',\n * header: 'Name',\n * filterType: 'text',\n * filterValue: (user) => user.name,\n * render: (user) => <span>{user.name}</span>,\n * },\n * {\n * key: 'status',\n * header: 'Status',\n * filterType: 'select',\n * filterOptions: [\n * { value: 'active', label: 'Active' },\n * { value: 'inactive', label: 'Inactive' },\n * ],\n * filterValue: (user) => user.status,\n * render: (user) => <Badge>{user.status}</Badge>,\n * },\n * ]\n *\n * <DataTable data={users} columns={columns} getRowKey={(u) => u.id} />\n * ```\n */\nexport function DataTable<T>({\n data,\n columns,\n getRowKey,\n onRowClick,\n loading,\n emptyMessage = 'Ingen data att visa.',\n className,\n showFilters = true,\n initialSortKey,\n initialSortDirection = 'asc',\n onFilteredDataChange,\n resizable = false,\n fixedLayout = false,\n}: DataTableProps<T>) {\n // Filter state: { columnKey: filterValue }\n const [filters, setFilters] = useState<Record<string, string | string[]>>({})\n\n // Sort state\n const [sortKey, setSortKey] = useState<string | null>(initialSortKey || null)\n const [sortDirection, setSortDirection] = useState<'asc' | 'desc'>(initialSortDirection)\n\n // Update filter for a specific column\n const handleFilterChange = useCallback((columnKey: string, value: string | string[]) => {\n setFilters((prev) => {\n const next = { ...prev }\n if (value === '' || (Array.isArray(value) && value.length === 0)) {\n delete next[columnKey]\n } else {\n next[columnKey] = value\n }\n return next\n })\n }, [])\n\n // Clear all filters\n const clearFilters = useCallback(() => {\n setFilters({})\n }, [])\n\n // Apply filtering\n const filteredData = useMemo(() => {\n let result = [...data]\n\n // Apply each filter\n for (const [columnKey, filterValue] of Object.entries(filters)) {\n if (!filterValue || (Array.isArray(filterValue) && filterValue.length === 0)) continue\n\n const column = columns.find((c) => c.key === columnKey)\n if (!column) continue\n\n const getFilterableValue = column.filterValue || ((item: T) => {\n // Default: try to access item[columnKey]\n return (item as Record<string, unknown>)[columnKey]\n })\n\n result = result.filter((item) => {\n const itemValue = getFilterableValue(item)\n\n // Handle null/undefined\n if (itemValue === null || itemValue === undefined) {\n return filterValue === ''\n }\n\n const filterType = column.filterType ?? 'text'\n\n // Boolean filter\n if (filterType === 'boolean') {\n const boolFilterValue = filterValue === 'true'\n return itemValue === boolFilterValue\n }\n\n // Multiselect filter\n if (filterType === 'multiselect' && Array.isArray(filterValue)) {\n return filterValue.includes(String(itemValue))\n }\n\n // Select filter (exact match)\n if (filterType === 'select') {\n return String(itemValue).toLowerCase() === String(filterValue).toLowerCase()\n }\n\n // Text filter (partial match, case insensitive)\n return String(itemValue).toLowerCase().includes(String(filterValue).toLowerCase())\n })\n }\n\n return result\n }, [data, filters, columns])\n\n // Apply sorting\n const sortedData = useMemo(() => {\n if (!sortKey) return filteredData\n\n const column = columns.find((c) => c.key === sortKey)\n if (!column) return filteredData\n\n const sorted = [...filteredData].sort((a, b) => {\n // Use custom sort function if provided\n if (column.sortFn) {\n return column.sortFn(a, b)\n }\n\n // Default sort: use filterValue getter or column key\n const getValueForSort = column.filterValue || ((item: T) => {\n return (item as Record<string, unknown>)[sortKey]\n })\n\n const aVal = getValueForSort(a)\n const bVal = getValueForSort(b)\n\n // Handle null/undefined\n if (aVal === null || aVal === undefined) return 1\n if (bVal === null || bVal === undefined) return -1\n\n // Compare strings\n if (typeof aVal === 'string' && typeof bVal === 'string') {\n return aVal.localeCompare(bVal, 'sv')\n }\n\n // Compare numbers/booleans\n if (aVal < bVal) return -1\n if (aVal > bVal) return 1\n return 0\n })\n\n return sortDirection === 'desc' ? sorted.reverse() : sorted\n }, [filteredData, sortKey, sortDirection, columns])\n\n // Notify parent when filtered data changes\n useEffect(() => {\n onFilteredDataChange?.(sortedData)\n }, [sortedData, onFilteredDataChange])\n\n // Handle column header click for sorting\n const handleSort = useCallback((columnKey: string) => {\n if (sortKey === columnKey) {\n // Toggle direction\n setSortDirection((prev) => (prev === 'asc' ? 'desc' : 'asc'))\n } else {\n // New sort column\n setSortKey(columnKey)\n setSortDirection('asc')\n }\n }, [sortKey])\n\n // Transform columns to include sort click handlers\n const tableColumns = useMemo(() => {\n return columns.map((column) => {\n const isSortable = column.sortable !== false && column.filterType !== 'none'\n const isCurrentSort = sortKey === column.key\n\n return {\n key: column.key,\n header: isSortable ? (\n <button\n onClick={() => handleSort(column.key)}\n className=\"flex items-center gap-1 hover:text-gray-900 transition-colors w-full text-left\"\n >\n {column.header}\n {isCurrentSort ? (\n <span className=\"text-primary-600\">\n {sortDirection === 'asc' ? '↑' : '↓'}\n </span>\n ) : (\n <span className=\"text-gray-400 opacity-50\">↕</span>\n )}\n </button>\n ) : column.header,\n render: column.render,\n width: column.width,\n align: column.align,\n sortable: false, // We handle sorting ourselves\n } as TableColumn<T>\n })\n }, [columns, sortKey, sortDirection, handleSort])\n\n const hasActiveFilters = Object.keys(filters).length > 0\n\n return (\n <div className={className}>\n {/* Filter Row */}\n {showFilters && (\n <div className=\"mb-4\">\n <div className=\"flex flex-wrap items-center gap-2 mb-2\">\n <span className=\"text-sm text-gray-500\">\n Visar {sortedData.length} av {data.length}\n </span>\n {hasActiveFilters && (\n <button\n onClick={clearFilters}\n className=\"text-sm text-primary-600 hover:underline\"\n >\n Rensa filter\n </button>\n )}\n </div>\n {/* Responsive grid: stack on mobile, side-by-side on larger screens */}\n <div className=\"grid grid-cols-1 sm:grid-cols-2 md:grid-cols-3 lg:grid-cols-4 xl:grid-cols-6 gap-3 p-3 bg-gray-50 border border-gray-200 rounded-lg\">\n {columns\n .filter((col) => col.filterType !== 'none')\n .map((column) => (\n <div key={column.key} className=\"min-w-0\">\n <label className=\"text-xs text-gray-500 mb-1 block truncate\">\n {column.header}\n </label>\n <ColumnFilter\n column={column as DataTableColumn<unknown>}\n value={filters[column.key] || ''}\n onChange={(value) => handleFilterChange(column.key, value)}\n />\n </div>\n ))}\n </div>\n </div>\n )}\n\n {/* Table */}\n <Table\n data={sortedData}\n columns={tableColumns}\n getRowKey={getRowKey}\n onRowClick={onRowClick}\n loading={loading}\n emptyMessage={emptyMessage}\n resizable={resizable}\n fixedLayout={fixedLayout}\n />\n </div>\n )\n}\n\n// ===========================================\n// Utility: Create filter options from data\n// ===========================================\n\n/**\n * Create filter options from data array.\n * Extracts unique values and creates option objects.\n *\n * @example\n * ```tsx\n * const statusOptions = createFilterOptions(\n * users,\n * (user) => user.status,\n * { active: 'Active', inactive: 'Inactive' }\n * )\n * ```\n */\nexport function createFilterOptions<T>(\n data: T[],\n getValue: (item: T) => string | null | undefined,\n labelMap?: Record<string, string>\n): FilterOption[] {\n const uniqueValues = new Set<string>()\n\n for (const item of data) {\n const value = getValue(item)\n if (value !== null && value !== undefined && value !== '') {\n uniqueValues.add(value)\n }\n }\n\n return Array.from(uniqueValues)\n .sort((a, b) => a.localeCompare(b, 'sv'))\n .map((value) => ({\n value,\n label: labelMap?.[value] || value,\n }))\n}\n","import { useState, useRef, useEffect, useMemo, ReactNode, KeyboardEvent } from 'react'\n\nexport interface SelectOption<T = string> {\n /** Unique value for the option */\n value: T\n /** Display label */\n label: string\n /** Optional icon or element to display */\n icon?: ReactNode\n /** Whether this option is disabled */\n disabled?: boolean\n}\n\ninterface SelectProps<T = string> {\n /** Available options */\n options: SelectOption<T>[]\n /** Currently selected value(s) */\n value: T | T[] | null\n /** Called when selection changes */\n onChange: (value: T | T[] | null) => void\n /** Placeholder text when nothing selected */\n placeholder?: string\n /** Label text */\n label?: string\n /** Error message */\n error?: string\n /** Whether search is enabled */\n searchable?: boolean\n /** Whether multiple selection is allowed */\n multiple?: boolean\n /** Whether the select is disabled */\n disabled?: boolean\n /** Additional class names */\n className?: string\n}\n\n/**\n * Select component with searchable dropdown and multi-select support.\n */\nexport function Select<T = string>({\n options,\n value,\n onChange,\n placeholder = 'Select...',\n label,\n error,\n searchable = true,\n multiple = false,\n disabled = false,\n className = '',\n}: SelectProps<T>) {\n const [isOpen, setIsOpen] = useState(false)\n const [searchTerm, setSearchTerm] = useState('')\n const [highlightedIndex, setHighlightedIndex] = useState(0)\n const containerRef = useRef<HTMLDivElement>(null)\n const inputRef = useRef<HTMLInputElement>(null)\n\n // Filter options based on search term\n const filteredOptions = useMemo(() => {\n if (!searchTerm) return options\n const term = searchTerm.toLowerCase()\n return options.filter((opt) => opt.label.toLowerCase().includes(term))\n }, [options, searchTerm])\n\n // Get selected options\n const selectedOptions = useMemo(() => {\n if (value === null) return []\n const values = Array.isArray(value) ? value : [value]\n return options.filter((opt) => values.includes(opt.value))\n }, [options, value])\n\n // Display text\n const displayText = useMemo(() => {\n if (selectedOptions.length === 0) return ''\n if (multiple) {\n return selectedOptions.map((opt) => opt.label).join(', ')\n }\n return selectedOptions[0]?.label ?? ''\n }, [selectedOptions, multiple])\n\n // Close on outside click\n useEffect(() => {\n const handleClickOutside = (e: MouseEvent) => {\n if (containerRef.current && !containerRef.current.contains(e.target as Node)) {\n setIsOpen(false)\n setSearchTerm('')\n }\n }\n document.addEventListener('mousedown', handleClickOutside)\n return () => document.removeEventListener('mousedown', handleClickOutside)\n }, [])\n\n // Reset highlighted index when filtered options change\n useEffect(() => {\n setHighlightedIndex(0)\n }, [filteredOptions])\n\n const handleSelect = (option: SelectOption<T>) => {\n if (option.disabled) return\n\n if (multiple) {\n const currentValues = Array.isArray(value) ? value : value ? [value] : []\n const isSelected = currentValues.includes(option.value)\n if (isSelected) {\n const newValues = currentValues.filter((v) => v !== option.value)\n onChange(newValues.length > 0 ? newValues : null)\n } else {\n onChange([...currentValues, option.value])\n }\n } else {\n onChange(option.value)\n setIsOpen(false)\n setSearchTerm('')\n }\n }\n\n const handleKeyDown = (e: KeyboardEvent) => {\n if (disabled) return\n\n switch (e.key) {\n case 'ArrowDown':\n e.preventDefault()\n if (!isOpen) {\n setIsOpen(true)\n } else {\n setHighlightedIndex((prev) => Math.min(prev + 1, filteredOptions.length - 1))\n }\n break\n case 'ArrowUp':\n e.preventDefault()\n setHighlightedIndex((prev) => Math.max(prev - 1, 0))\n break\n case 'Enter':\n e.preventDefault()\n if (isOpen && filteredOptions[highlightedIndex]) {\n handleSelect(filteredOptions[highlightedIndex])\n } else {\n setIsOpen(true)\n }\n break\n case 'Escape':\n setIsOpen(false)\n setSearchTerm('')\n break\n }\n }\n\n const isSelected = (option: SelectOption<T>) => {\n if (value === null) return false\n const values = Array.isArray(value) ? value : [value]\n return values.includes(option.value)\n }\n\n return (\n <div ref={containerRef} className={`relative ${className}`}>\n {label && (\n <label className=\"block text-sm font-medium text-gray-700 mb-2\">{label}</label>\n )}\n\n <div\n className={`\n relative w-full px-4 py-3 rounded-xl border bg-white\n ${disabled ? 'bg-gray-100 cursor-not-allowed' : 'cursor-pointer'}\n ${error ? 'border-red-300' : isOpen ? 'border-primary-500 ring-2 ring-primary-100' : 'border-gray-200'}\n transition-all\n `}\n onClick={() => {\n if (!disabled) {\n setIsOpen(!isOpen)\n if (!isOpen && searchable) {\n setTimeout(() => inputRef.current?.focus(), 0)\n }\n }\n }}\n onKeyDown={handleKeyDown}\n tabIndex={disabled ? -1 : 0}\n >\n <div className=\"flex items-center justify-between\">\n {searchable && isOpen ? (\n <input\n ref={inputRef}\n type=\"text\"\n className=\"w-full outline-none bg-transparent\"\n placeholder={displayText || placeholder}\n value={searchTerm}\n onChange={(e) => setSearchTerm(e.target.value)}\n onClick={(e) => e.stopPropagation()}\n />\n ) : (\n <span className={displayText ? 'text-gray-800' : 'text-gray-400'}>\n {displayText || placeholder}\n </span>\n )}\n <svg\n className={`w-5 h-5 text-gray-400 transition-transform ${isOpen ? 'rotate-180' : ''}`}\n fill=\"none\"\n stroke=\"currentColor\"\n viewBox=\"0 0 24 24\"\n >\n <path strokeLinecap=\"round\" strokeLinejoin=\"round\" strokeWidth={2} d=\"M19 9l-7 7-7-7\" />\n </svg>\n </div>\n </div>\n\n {error && <p className=\"mt-1 text-xs text-red-600\">{error}</p>}\n\n {isOpen && (\n <div className=\"absolute z-50 w-full mt-1 bg-white border border-gray-200 rounded-xl shadow-lg max-h-60 overflow-auto\">\n {filteredOptions.length === 0 ? (\n <div className=\"px-4 py-3 text-sm text-gray-500\">No options found</div>\n ) : (\n filteredOptions.map((option, index) => (\n <div\n key={String(option.value)}\n className={`\n px-4 py-3 text-sm cursor-pointer flex items-center gap-2\n ${option.disabled ? 'text-gray-400 cursor-not-allowed' : 'text-gray-800'}\n ${highlightedIndex === index ? 'bg-primary-50' : 'hover:bg-gray-50'}\n ${isSelected(option) ? 'bg-primary-50 font-medium' : ''}\n `}\n onClick={(e) => {\n e.stopPropagation()\n handleSelect(option)\n }}\n onMouseEnter={() => setHighlightedIndex(index)}\n >\n {multiple && (\n <div\n className={`\n w-4 h-4 border rounded flex items-center justify-center\n ${isSelected(option) ? 'bg-primary-600 border-primary-600' : 'border-gray-300'}\n `}\n >\n {isSelected(option) && (\n <svg className=\"w-3 h-3 text-white\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path strokeLinecap=\"round\" strokeLinejoin=\"round\" strokeWidth={3} d=\"M5 13l4 4L19 7\" />\n </svg>\n )}\n </div>\n )}\n {option.icon}\n <span>{option.label}</span>\n </div>\n ))\n )}\n </div>\n )}\n </div>\n )\n}\n","import { useState, ReactNode, KeyboardEvent } from 'react'\n\nexport interface Tab {\n /** Unique identifier for the tab */\n id: string\n /** Tab label */\n label: string\n /** Optional icon */\n icon?: ReactNode\n /** Whether the tab is disabled */\n disabled?: boolean\n /** Tab content (for uncontrolled mode) */\n content?: ReactNode\n}\n\ninterface TabsProps {\n /** Tab definitions */\n tabs: Tab[]\n /** Currently active tab id (controlled mode) */\n activeTab?: string\n /** Called when tab changes */\n onTabChange?: (tabId: string) => void\n /** Default active tab (uncontrolled mode) */\n defaultTab?: string\n /** Tab variant */\n variant?: 'default' | 'pills' | 'underline'\n /** Whether to render tab content (set to false if rendering content externally) */\n renderContent?: boolean\n /** Additional class names for the tabs container */\n className?: string\n}\n\n/**\n * Tabs component for tab navigation with multiple style variants.\n */\nexport function Tabs({\n tabs,\n activeTab: controlledActiveTab,\n onTabChange,\n defaultTab,\n variant = 'default',\n renderContent = true,\n className = '',\n}: TabsProps) {\n const isControlled = controlledActiveTab !== undefined\n const [internalActiveTab, setInternalActiveTab] = useState(\n defaultTab || tabs.find((t) => !t.disabled)?.id || tabs[0]?.id\n )\n\n const activeTab = isControlled ? controlledActiveTab : internalActiveTab\n\n const handleTabClick = (tab: Tab) => {\n if (tab.disabled) return\n\n if (!isControlled) {\n setInternalActiveTab(tab.id)\n }\n onTabChange?.(tab.id)\n }\n\n const handleKeyDown = (e: KeyboardEvent, index: number) => {\n const enabledTabs = tabs.filter((t) => !t.disabled)\n const currentEnabledIndex = enabledTabs.findIndex((t) => t.id === tabs[index].id)\n\n let newTab: Tab | undefined\n\n switch (e.key) {\n case 'ArrowLeft':\n e.preventDefault()\n newTab = enabledTabs[currentEnabledIndex - 1] || enabledTabs[enabledTabs.length - 1]\n break\n case 'ArrowRight':\n e.preventDefault()\n newTab = enabledTabs[currentEnabledIndex + 1] || enabledTabs[0]\n break\n case 'Home':\n e.preventDefault()\n newTab = enabledTabs[0]\n break\n case 'End':\n e.preventDefault()\n newTab = enabledTabs[enabledTabs.length - 1]\n break\n }\n\n if (newTab) {\n handleTabClick(newTab)\n // Focus the new tab button\n const button = document.querySelector(`[data-tab-id=\"${newTab.id}\"]`) as HTMLElement\n button?.focus()\n }\n }\n\n const activeContent = tabs.find((t) => t.id === activeTab)?.content\n\n // Variant styles\n const variantStyles = {\n default: {\n container: 'border-b border-gray-200',\n tab: (isActive: boolean, isDisabled: boolean) => `\n px-4 py-3 text-sm font-medium border-b-2 -mb-px transition-colors\n ${isDisabled ? 'text-gray-300 cursor-not-allowed' : 'cursor-pointer'}\n ${isActive\n ? 'border-primary-500 text-primary-600'\n : isDisabled\n ? 'border-transparent'\n : 'border-transparent text-gray-500 hover:text-gray-700 hover:border-gray-300'\n }\n `,\n },\n pills: {\n container: 'bg-gray-100 rounded-lg p-1 inline-flex',\n tab: (isActive: boolean, isDisabled: boolean) => `\n px-4 py-2 text-sm font-medium rounded-md transition-colors\n ${isDisabled ? 'text-gray-400 cursor-not-allowed' : 'cursor-pointer'}\n ${isActive\n ? 'bg-white text-gray-900 shadow-sm'\n : isDisabled\n ? ''\n : 'text-gray-500 hover:text-gray-700'\n }\n `,\n },\n underline: {\n container: '',\n tab: (isActive: boolean, isDisabled: boolean) => `\n px-4 py-2 text-sm font-medium transition-colors relative\n ${isDisabled ? 'text-gray-300 cursor-not-allowed' : 'cursor-pointer'}\n ${isActive\n ? 'text-primary-600'\n : isDisabled\n ? ''\n : 'text-gray-500 hover:text-gray-700'\n }\n ${isActive ? 'after:absolute after:bottom-0 after:left-0 after:right-0 after:h-0.5 after:bg-primary-500' : ''}\n `,\n },\n }\n\n const styles = variantStyles[variant]\n\n return (\n <div className={className}>\n {/* Tab list */}\n <div className={`flex ${styles.container}`} role=\"tablist\">\n {tabs.map((tab, index) => {\n const isActive = tab.id === activeTab\n const isDisabled = tab.disabled ?? false\n\n return (\n <button\n key={tab.id}\n type=\"button\"\n role=\"tab\"\n data-tab-id={tab.id}\n aria-selected={isActive}\n aria-disabled={isDisabled}\n tabIndex={isActive ? 0 : -1}\n className={styles.tab(isActive, isDisabled)}\n onClick={() => handleTabClick(tab)}\n onKeyDown={(e) => handleKeyDown(e, index)}\n >\n <span className=\"flex items-center gap-2\">\n {tab.icon}\n {tab.label}\n </span>\n </button>\n )\n })}\n </div>\n\n {/* Tab content */}\n {renderContent && activeContent && (\n <div className=\"pt-4\" role=\"tabpanel\">\n {activeContent}\n </div>\n )}\n </div>\n )\n}\n","import { useState, useRef, useEffect, useMemo } from 'react'\n\nexport interface DateRange {\n start: Date | null\n end: Date | null\n}\n\ninterface DatePickerProps {\n /** Selected date (single mode) or date range (range mode) */\n value: Date | DateRange | null\n /** Called when date selection changes */\n onChange: (value: Date | DateRange | null) => void\n /** Whether to enable range selection */\n range?: boolean\n /** Label text */\n label?: string\n /** Placeholder text */\n placeholder?: string\n /** Error message */\n error?: string\n /** Minimum selectable date */\n minDate?: Date\n /** Maximum selectable date */\n maxDate?: Date\n /** Whether the picker is disabled */\n disabled?: boolean\n /** Additional class names */\n className?: string\n}\n\nconst WEEKDAYS = ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun']\nconst MONTHS = [\n 'January', 'February', 'March', 'April', 'May', 'June',\n 'July', 'August', 'September', 'October', 'November', 'December'\n]\n\ninterface PresetRange {\n label: string\n getValue: () => DateRange\n}\n\nconst PRESET_RANGES: PresetRange[] = [\n {\n label: 'Today',\n getValue: () => {\n const today = new Date()\n today.setHours(0, 0, 0, 0)\n return { start: today, end: today }\n },\n },\n {\n label: 'Yesterday',\n getValue: () => {\n const yesterday = new Date()\n yesterday.setDate(yesterday.getDate() - 1)\n yesterday.setHours(0, 0, 0, 0)\n return { start: yesterday, end: yesterday }\n },\n },\n {\n label: 'Last 7 days',\n getValue: () => {\n const end = new Date()\n end.setHours(0, 0, 0, 0)\n const start = new Date()\n start.setDate(start.getDate() - 6)\n start.setHours(0, 0, 0, 0)\n return { start, end }\n },\n },\n {\n label: 'Last 30 days',\n getValue: () => {\n const end = new Date()\n end.setHours(0, 0, 0, 0)\n const start = new Date()\n start.setDate(start.getDate() - 29)\n start.setHours(0, 0, 0, 0)\n return { start, end }\n },\n },\n {\n label: 'This month',\n getValue: () => {\n const start = new Date()\n start.setDate(1)\n start.setHours(0, 0, 0, 0)\n const end = new Date()\n end.setHours(0, 0, 0, 0)\n return { start, end }\n },\n },\n {\n label: 'Last month',\n getValue: () => {\n const start = new Date()\n start.setMonth(start.getMonth() - 1)\n start.setDate(1)\n start.setHours(0, 0, 0, 0)\n const end = new Date(start.getFullYear(), start.getMonth() + 1, 0)\n end.setHours(0, 0, 0, 0)\n return { start, end }\n },\n },\n]\n\nfunction formatDate(date: Date): string {\n return date.toLocaleDateString('sv-SE') // YYYY-MM-DD format\n}\n\nfunction isSameDay(a: Date, b: Date): boolean {\n return a.getDate() === b.getDate() &&\n a.getMonth() === b.getMonth() &&\n a.getFullYear() === b.getFullYear()\n}\n\nfunction isInRange(date: Date, range: DateRange): boolean {\n if (!range.start || !range.end) return false\n const d = date.getTime()\n return d >= range.start.getTime() && d <= range.end.getTime()\n}\n\n/**\n * DatePicker component with single date and date range support.\n */\nexport function DatePicker({\n value,\n onChange,\n range = false,\n label,\n placeholder = 'Select date',\n error,\n minDate,\n maxDate,\n disabled = false,\n className = '',\n}: DatePickerProps) {\n const [isOpen, setIsOpen] = useState(false)\n const [viewDate, setViewDate] = useState(new Date())\n const [hoverDate, setHoverDate] = useState<Date | null>(null)\n const containerRef = useRef<HTMLDivElement>(null)\n\n // For range selection - track if we're selecting start or end\n const [selectingEnd, setSelectingEnd] = useState(false)\n\n // Close on outside click\n useEffect(() => {\n const handleClickOutside = (e: MouseEvent) => {\n if (containerRef.current && !containerRef.current.contains(e.target as Node)) {\n setIsOpen(false)\n setSelectingEnd(false)\n }\n }\n document.addEventListener('mousedown', handleClickOutside)\n return () => document.removeEventListener('mousedown', handleClickOutside)\n }, [])\n\n // Get display text\n const displayText = useMemo(() => {\n if (!value) return ''\n if (range) {\n const rangeValue = value as DateRange\n if (rangeValue.start && rangeValue.end) {\n if (isSameDay(rangeValue.start, rangeValue.end)) {\n return formatDate(rangeValue.start)\n }\n return `${formatDate(rangeValue.start)} - ${formatDate(rangeValue.end)}`\n }\n if (rangeValue.start) {\n return `${formatDate(rangeValue.start)} - ...`\n }\n return ''\n }\n return formatDate(value as Date)\n }, [value, range])\n\n // Generate calendar days\n const calendarDays = useMemo(() => {\n const year = viewDate.getFullYear()\n const month = viewDate.getMonth()\n const firstDay = new Date(year, month, 1)\n const lastDay = new Date(year, month + 1, 0)\n\n // Get Monday-based day of week (0 = Monday)\n let startDayOfWeek = firstDay.getDay() - 1\n if (startDayOfWeek < 0) startDayOfWeek = 6\n\n const days: (Date | null)[] = []\n\n // Add empty slots for days before the first of the month\n for (let i = 0; i < startDayOfWeek; i++) {\n days.push(null)\n }\n\n // Add all days of the month\n for (let i = 1; i <= lastDay.getDate(); i++) {\n days.push(new Date(year, month, i))\n }\n\n return days\n }, [viewDate])\n\n const handleDateClick = (date: Date) => {\n if (isDateDisabled(date)) return\n\n if (range) {\n const rangeValue = (value as DateRange) || { start: null, end: null }\n\n if (!selectingEnd || !rangeValue.start) {\n // Selecting start date\n onChange({ start: date, end: null })\n setSelectingEnd(true)\n } else {\n // Selecting end date\n if (date < rangeValue.start) {\n // If end is before start, swap them\n onChange({ start: date, end: rangeValue.start })\n } else {\n onChange({ start: rangeValue.start, end: date })\n }\n setSelectingEnd(false)\n setIsOpen(false)\n }\n } else {\n onChange(date)\n setIsOpen(false)\n }\n }\n\n const handlePresetClick = (preset: PresetRange) => {\n const rangeVal = preset.getValue()\n onChange(rangeVal)\n setIsOpen(false)\n setSelectingEnd(false)\n }\n\n const isDateDisabled = (date: Date): boolean => {\n if (minDate && date < minDate) return true\n if (maxDate && date > maxDate) return true\n return false\n }\n\n const isDateSelected = (date: Date): boolean => {\n if (!value) return false\n if (range) {\n const rangeValue = value as DateRange\n if (rangeValue.start && isSameDay(date, rangeValue.start)) return true\n if (rangeValue.end && isSameDay(date, rangeValue.end)) return true\n return false\n }\n return isSameDay(date, value as Date)\n }\n\n const isDateInRange = (date: Date): boolean => {\n if (!range || !value) return false\n const rangeValue = value as DateRange\n\n // If selecting end date and hovering, show preview range\n if (selectingEnd && rangeValue.start && hoverDate) {\n const previewRange: DateRange = {\n start: rangeValue.start,\n end: hoverDate > rangeValue.start ? hoverDate : rangeValue.start,\n }\n if (hoverDate < rangeValue.start) {\n previewRange.start = hoverDate\n previewRange.end = rangeValue.start\n }\n return isInRange(date, previewRange)\n }\n\n if (!rangeValue.start || !rangeValue.end) return false\n return isInRange(date, rangeValue)\n }\n\n const goToPrevMonth = () => {\n setViewDate(new Date(viewDate.getFullYear(), viewDate.getMonth() - 1, 1))\n }\n\n const goToNextMonth = () => {\n setViewDate(new Date(viewDate.getFullYear(), viewDate.getMonth() + 1, 1))\n }\n\n const today = new Date()\n today.setHours(0, 0, 0, 0)\n\n return (\n <div ref={containerRef} className={`relative ${className}`}>\n {label && (\n <label className=\"block text-sm font-medium text-gray-700 mb-2\">{label}</label>\n )}\n\n <div\n className={`\n relative w-full px-4 py-3 rounded-xl border bg-white\n ${disabled ? 'bg-gray-100 cursor-not-allowed' : 'cursor-pointer'}\n ${error ? 'border-red-300' : isOpen ? 'border-primary-500 ring-2 ring-primary-100' : 'border-gray-200'}\n transition-all\n `}\n onClick={() => !disabled && setIsOpen(!isOpen)}\n >\n <div className=\"flex items-center justify-between\">\n <span className={displayText ? 'text-gray-800' : 'text-gray-400'}>\n {displayText || placeholder}\n </span>\n <svg className=\"w-5 h-5 text-gray-400\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path strokeLinecap=\"round\" strokeLinejoin=\"round\" strokeWidth={2} d=\"M8 7V3m8 4V3m-9 8h10M5 21h14a2 2 0 002-2V7a2 2 0 00-2-2H5a2 2 0 00-2 2v12a2 2 0 002 2z\" />\n </svg>\n </div>\n </div>\n\n {error && <p className=\"mt-1 text-xs text-red-600\">{error}</p>}\n\n {isOpen && (\n <div className=\"absolute z-50 mt-1 bg-white border border-gray-200 rounded-xl shadow-lg p-4\">\n <div className={range ? 'flex gap-4' : ''}>\n {/* Preset ranges (only for range mode) */}\n {range && (\n <div className=\"border-r border-gray-100 pr-4 space-y-1\">\n {PRESET_RANGES.map((preset) => (\n <button\n key={preset.label}\n type=\"button\"\n className=\"block w-full text-left px-3 py-2 text-sm text-gray-700 hover:bg-gray-50 rounded-lg\"\n onClick={() => handlePresetClick(preset)}\n >\n {preset.label}\n </button>\n ))}\n </div>\n )}\n\n {/* Calendar */}\n <div>\n {/* Month navigation */}\n <div className=\"flex items-center justify-between mb-4\">\n <button\n type=\"button\"\n className=\"p-1 hover:bg-gray-100 rounded\"\n onClick={goToPrevMonth}\n >\n <svg className=\"w-5 h-5 text-gray-600\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path strokeLinecap=\"round\" strokeLinejoin=\"round\" strokeWidth={2} d=\"M15 19l-7-7 7-7\" />\n </svg>\n </button>\n <span className=\"text-sm font-semibold text-gray-800\">\n {MONTHS[viewDate.getMonth()]} {viewDate.getFullYear()}\n </span>\n <button\n type=\"button\"\n className=\"p-1 hover:bg-gray-100 rounded\"\n onClick={goToNextMonth}\n >\n <svg className=\"w-5 h-5 text-gray-600\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path strokeLinecap=\"round\" strokeLinejoin=\"round\" strokeWidth={2} d=\"M9 5l7 7-7 7\" />\n </svg>\n </button>\n </div>\n\n {/* Weekday headers */}\n <div className=\"grid grid-cols-7 gap-1 mb-2\">\n {WEEKDAYS.map((day) => (\n <div key={day} className=\"text-center text-xs font-medium text-gray-500 py-1\">\n {day}\n </div>\n ))}\n </div>\n\n {/* Calendar days */}\n <div className=\"grid grid-cols-7 gap-1\">\n {calendarDays.map((date, index) => {\n if (!date) {\n return <div key={`empty-${index}`} className=\"w-9 h-9\" />\n }\n\n const isDisabled = isDateDisabled(date)\n const isSelected = isDateSelected(date)\n const inRange = isDateInRange(date)\n const isToday = isSameDay(date, today)\n\n return (\n <button\n key={date.toISOString()}\n type=\"button\"\n className={`\n w-9 h-9 text-sm rounded-lg transition-colors\n ${isDisabled ? 'text-gray-300 cursor-not-allowed' : 'hover:bg-gray-100'}\n ${isSelected ? 'bg-primary-600 text-white hover:bg-primary-700' : ''}\n ${inRange && !isSelected ? 'bg-primary-100' : ''}\n ${isToday && !isSelected ? 'ring-1 ring-primary-400' : ''}\n `}\n onClick={() => handleDateClick(date)}\n onMouseEnter={() => setHoverDate(date)}\n onMouseLeave={() => setHoverDate(null)}\n disabled={isDisabled}\n >\n {date.getDate()}\n </button>\n )\n })}\n </div>\n </div>\n </div>\n </div>\n )}\n </div>\n )\n}\n","import { useState, useEffect, useCallback, useRef } from 'react'\n\nexport interface TimerState {\n /** Whether the timer is currently running */\n isRunning: boolean\n /** Total elapsed time in seconds */\n elapsedSeconds: number\n /** When the timer was started (if running) */\n startedAt: Date | null\n}\n\ninterface TimerProps {\n /** Initial elapsed time in seconds (default: 0) */\n initialSeconds?: number\n /** Called when timer starts */\n onStart?: (startedAt: Date) => void\n /** Called when timer stops */\n onStop?: (elapsedSeconds: number) => void\n /** Called when timer is reset */\n onReset?: () => void\n /** Called every second while running (useful for auto-save) */\n onTick?: (elapsedSeconds: number) => void\n /** Whether to show the reset button */\n showReset?: boolean\n /** Size variant */\n size?: 'sm' | 'md' | 'lg'\n /** Additional class names */\n className?: string\n /** External control - if provided, component becomes controlled */\n isRunning?: boolean\n /** External elapsed seconds - for controlled mode */\n elapsedSeconds?: number\n}\n\nfunction formatTime(totalSeconds: number): string {\n const hours = Math.floor(totalSeconds / 3600)\n const minutes = Math.floor((totalSeconds % 3600) / 60)\n const seconds = totalSeconds % 60\n\n const pad = (n: number) => n.toString().padStart(2, '0')\n\n if (hours > 0) {\n return `${pad(hours)}:${pad(minutes)}:${pad(seconds)}`\n }\n return `${pad(minutes)}:${pad(seconds)}`\n}\n\n/**\n * Timer component for time tracking with play/pause/stop controls.\n */\nexport function Timer({\n initialSeconds = 0,\n onStart,\n onStop,\n onReset,\n onTick,\n showReset = true,\n size = 'md',\n className = '',\n isRunning: controlledIsRunning,\n elapsedSeconds: controlledElapsedSeconds,\n}: TimerProps) {\n // Determine if we're in controlled or uncontrolled mode\n const isControlled = controlledIsRunning !== undefined\n\n const [internalIsRunning, setInternalIsRunning] = useState(false)\n const [internalElapsedSeconds, setInternalElapsedSeconds] = useState(initialSeconds)\n\n const isRunning = isControlled ? controlledIsRunning : internalIsRunning\n const elapsedSeconds = isControlled ? (controlledElapsedSeconds ?? 0) : internalElapsedSeconds\n\n const intervalRef = useRef<ReturnType<typeof setInterval> | null>(null)\n const startTimeRef = useRef<Date | null>(null)\n\n // Clean up interval on unmount\n useEffect(() => {\n return () => {\n if (intervalRef.current) {\n clearInterval(intervalRef.current)\n }\n }\n }, [])\n\n // Handle ticking in uncontrolled mode\n useEffect(() => {\n if (isControlled) return // In controlled mode, parent handles ticking\n\n if (isRunning) {\n intervalRef.current = setInterval(() => {\n setInternalElapsedSeconds((prev) => {\n const newValue = prev + 1\n onTick?.(newValue)\n return newValue\n })\n }, 1000)\n } else {\n if (intervalRef.current) {\n clearInterval(intervalRef.current)\n intervalRef.current = null\n }\n }\n\n return () => {\n if (intervalRef.current) {\n clearInterval(intervalRef.current)\n intervalRef.current = null\n }\n }\n }, [isRunning, isControlled, onTick])\n\n const handleStart = useCallback(() => {\n const now = new Date()\n startTimeRef.current = now\n\n if (!isControlled) {\n setInternalIsRunning(true)\n }\n\n onStart?.(now)\n }, [isControlled, onStart])\n\n const handleStop = useCallback(() => {\n if (!isControlled) {\n setInternalIsRunning(false)\n }\n\n onStop?.(elapsedSeconds)\n }, [isControlled, elapsedSeconds, onStop])\n\n const handleReset = useCallback(() => {\n if (!isControlled) {\n setInternalIsRunning(false)\n setInternalElapsedSeconds(0)\n }\n\n startTimeRef.current = null\n onReset?.()\n }, [isControlled, onReset])\n\n const handleToggle = useCallback(() => {\n if (isRunning) {\n handleStop()\n } else {\n handleStart()\n }\n }, [isRunning, handleStart, handleStop])\n\n // Size variants\n const sizeClasses = {\n sm: {\n container: 'gap-2',\n time: 'text-2xl',\n button: 'w-10 h-10',\n icon: 'w-4 h-4',\n },\n md: {\n container: 'gap-3',\n time: 'text-4xl',\n button: 'w-12 h-12',\n icon: 'w-5 h-5',\n },\n lg: {\n container: 'gap-4',\n time: 'text-5xl',\n button: 'w-14 h-14',\n icon: 'w-6 h-6',\n },\n }\n\n const styles = sizeClasses[size]\n\n return (\n <div className={`flex items-center ${styles.container} ${className}`}>\n {/* Time display */}\n <div className={`font-mono font-bold text-gray-800 ${styles.time} tabular-nums`}>\n {formatTime(elapsedSeconds)}\n </div>\n\n {/* Controls */}\n <div className=\"flex items-center gap-2\">\n {/* Play/Pause button */}\n <button\n type=\"button\"\n onClick={handleToggle}\n className={`\n ${styles.button} rounded-full flex items-center justify-center\n ${isRunning\n ? 'bg-amber-500 hover:bg-amber-600 text-white'\n : 'bg-green-500 hover:bg-green-600 text-white'\n }\n transition-colors focus:outline-none focus:ring-2 focus:ring-offset-2\n ${isRunning ? 'focus:ring-amber-500' : 'focus:ring-green-500'}\n `}\n title={isRunning ? 'Pause' : 'Start'}\n >\n {isRunning ? (\n // Pause icon\n <svg className={styles.icon} fill=\"currentColor\" viewBox=\"0 0 24 24\">\n <path d=\"M6 4h4v16H6V4zm8 0h4v16h-4V4z\" />\n </svg>\n ) : (\n // Play icon\n <svg className={styles.icon} fill=\"currentColor\" viewBox=\"0 0 24 24\">\n <path d=\"M8 5v14l11-7z\" />\n </svg>\n )}\n </button>\n\n {/* Stop button (only visible when timer has time) */}\n {elapsedSeconds > 0 && (\n <button\n type=\"button\"\n onClick={handleStop}\n className={`\n ${styles.button} rounded-full flex items-center justify-center\n bg-red-500 hover:bg-red-600 text-white\n transition-colors focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-red-500\n `}\n title=\"Stop\"\n >\n {/* Stop icon */}\n <svg className={styles.icon} fill=\"currentColor\" viewBox=\"0 0 24 24\">\n <path d=\"M6 6h12v12H6z\" />\n </svg>\n </button>\n )}\n\n {/* Reset button */}\n {showReset && elapsedSeconds > 0 && !isRunning && (\n <button\n type=\"button\"\n onClick={handleReset}\n className={`\n ${styles.button} rounded-full flex items-center justify-center\n bg-gray-200 hover:bg-gray-300 text-gray-700\n transition-colors focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-gray-400\n `}\n title=\"Reset\"\n >\n {/* Reset icon */}\n <svg className={styles.icon} fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path strokeLinecap=\"round\" strokeLinejoin=\"round\" strokeWidth={2} d=\"M4 4v5h.582m15.356 2A8.001 8.001 0 004.582 9m0 0H9m11 11v-5h-.581m0 0a8.003 8.003 0 01-15.357-2m15.357 2H15\" />\n </svg>\n </button>\n )}\n </div>\n </div>\n )\n}\n\n// Export helper function for external use\nexport { formatTime }\n"],"mappings":"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","names":["jsx","jsxs","jsx","jsx","jsx","jsxs","jsx","jsx","sizeClasses","jsx","jsxs","jsx","jsxs","forwardRef","jsx","jsxs","forwardRef","jsx","jsxs","jsx","jsxs","useState","jsx","jsxs","useState","useMemo","useCallback","useEffect","useState","useRef","useEffect","useMemo","jsx","jsxs","isSelected","jsx","jsxs","useState","useCallback","useMemo","useEffect","useState","jsx","jsxs","useState","useRef","useEffect","useMemo","jsx","jsxs","useState","useEffect","useCallback","useRef","jsx","jsxs","sizeClasses"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kreativa/ui",
3
- "version": "0.1.3",
3
+ "version": "0.1.5",
4
4
  "description": "Shared UI components for Kreativa applications",
5
5
  "main": "./dist/index.js",
6
6
  "module": "./dist/index.mjs",