@apotech-os/ui-sdk 0.7.0 → 0.8.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +3 -12
- package/dist/index.d.ts +3 -12
- package/dist/index.js.map +1 -1
- package/package.json +4 -2
package/dist/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/cn.ts","../src/hooks.ts","../src/utils.ts","../src/components.tsx"],"names":["twMerge","clsx","createContext","useContext","useState","useRef","useCallback","useEffect","cva","React","jsx","jsxs","Textarea","Checkbox"],"mappings":"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","file":"index.cjs","sourcesContent":["import { type ClassValue, clsx } from 'clsx';\nimport { twMerge } from 'tailwind-merge';\n\nexport function cn(...inputs: ClassValue[]): string {\n return twMerge(clsx(inputs));\n}\n","/**\n * Runtime hooks provided by the shell via @apotech-os/ui-sdk.\n *\n * These hooks are implemented by the shell and injected at runtime via the\n * import map. App pages call them without knowing the shell internals.\n *\n * The default implementations throw if called outside of the shell context\n * (which should never happen in production — the shell always provides them\n * via the import map before mounting an app page).\n */\n\nimport { useContext, createContext, useCallback, useEffect, useRef, useState } from 'react';\n\n// ---------------------------------------------------------------------------\n// AppContext\n// ---------------------------------------------------------------------------\n\nexport interface AppContextValue {\n /** The slug of the installed app owning this page. */\n appSlug: string;\n /** The page path within the app (e.g. 'attribution'). */\n pagePath: string;\n /** The active space id, when applicable. */\n spaceId?: string;\n /**\n * The current user's grant role on this app context, when the shell knows it.\n * Settings pages use it to render read-only fields below ADMIN instead of\n * letting the user discover the 403 at save time.\n */\n role?: 'VIEWER' | 'EDITOR' | 'ADMIN';\n}\n\nconst AppContextInternalCtx = createContext<AppContextValue | null>(null);\n\nexport const AppContextProvider = AppContextInternalCtx.Provider;\n\n/** Returns context info for the current app page (appSlug, pagePath, spaceId). */\nexport function useAppContext(): AppContextValue {\n const ctx = useContext(AppContextInternalCtx);\n if (!ctx) throw new Error('useAppContext must be used inside an app page mounted by the shell');\n return ctx;\n}\n\n// ---------------------------------------------------------------------------\n// AppApi\n// ---------------------------------------------------------------------------\n\nexport interface AppApiClient {\n /**\n * Perform a GET request to a platform-data endpoint.\n * The session cookie is forwarded automatically (same-origin, withCredentials).\n */\n get<T>(path: string, params?: Record<string, string>): Promise<T>;\n /**\n * Perform a POST request to a platform-data endpoint.\n */\n post<T>(path: string, body?: unknown): Promise<T>;\n /**\n * Perform a PUT request to a platform-data endpoint (e.g. write app settings).\n */\n put<T>(path: string, body?: unknown): Promise<T>;\n /**\n * Perform a PATCH request to a platform-data endpoint (e.g. update a record).\n */\n patch<T>(path: string, body?: unknown): Promise<T>;\n /**\n * Perform a DELETE request to a platform-data endpoint (e.g. delete a record).\n */\n delete<T>(path: string): Promise<T>;\n /**\n * Run one of this app's `uiInvoke` functions and get its return value back.\n *\n * This is the ONLY way a page can reach an integration: the action endpoint\n * requires an app token and refuses a browser session. The platform mints the\n * token server-side and runs the handler in-process.\n *\n * The function must be declared `trigger: { type: 'uiInvoke' }` in the\n * manifest, and the caller must hold its `minRole` (default EDITOR).\n *\n * Pass `idempotencyKey` for anything that must not run twice on a double\n * click — a concurrent duplicate is rejected with 409 INVOCATION_IN_FLIGHT.\n *\n * Throws AppInvokeError. `code === 'FUNCTION_REJECTED'` carries an app-authored\n * message that is safe to show the user; every other failure is generic on\n * purpose (raw provider errors can leak tokens or PII).\n */\n invoke<TResult, TInput = Record<string, unknown>>(\n functionName: string,\n input?: TInput,\n opts?: { idempotencyKey?: string; signal?: AbortSignal },\n ): Promise<TResult>;\n}\n\n/** Thrown by AppApiClient.invoke. */\nexport class AppInvokeError extends Error {\n constructor(\n readonly status: number,\n message: string,\n readonly code?: string,\n readonly invocationId?: string,\n ) {\n super(message);\n this.name = 'AppInvokeError';\n }\n}\n\nconst AppApiCtx = createContext<AppApiClient | null>(null);\n\nexport const AppApiProvider = AppApiCtx.Provider;\n\n/**\n * Returns an API client scoped to the current user session.\n * Requests go to /api/data/* with the session cookie (RBAC applies server-side).\n */\nexport function useAppApi(): AppApiClient {\n const client = useContext(AppApiCtx);\n if (!client) throw new Error('useAppApi must be used inside an app page mounted by the shell');\n return client;\n}\n\n// ---------------------------------------------------------------------------\n// AppSettings\n// ---------------------------------------------------------------------------\n\n/**\n * Reads and writes this app's settings (GET/PUT /data/apps/:appSlug/settings).\n *\n * The app slug comes from the surrounding AppContext, so a settings page only\n * has to describe its form. Values are the ones the server merged with the\n * `settings.fields` defaults declared in the manifest.\n *\n * Reading requires VIEWER, writing requires ADMIN. `save` never throws: it\n * reports through `saveError`, which carries the raw failure (422\n * SETTINGS_VALIDATION_FAILED with its per-key errors, or 403) so the page can\n * map it back onto its fields. A failed save leaves `settings` untouched.\n */\nexport function useAppSettings<T = Record<string, unknown>>(): {\n settings: T | undefined;\n isLoading: boolean;\n error: unknown;\n save: (patch: Partial<T>) => Promise<void>;\n isSaving: boolean;\n saveError: unknown;\n} {\n const { appSlug } = useAppContext();\n const api = useAppApi();\n const path = `/data/apps/${appSlug}/settings`;\n\n const [settings, setSettings] = useState<T | undefined>(undefined);\n const [isLoading, setIsLoading] = useState(true);\n const [error, setError] = useState<unknown>(undefined);\n const [isSaving, setIsSaving] = useState(false);\n const [saveError, setSaveError] = useState<unknown>(undefined);\n\n // The shell rebuilds the client on every render, so it cannot be an effect\n // dependency without refetching in a loop.\n const clientRef = useRef(api);\n clientRef.current = api;\n // Bumped by every request and by unmount: a superseded or late response is\n // dropped instead of overwriting fresher state.\n const requestIdRef = useRef(0);\n const isMountedRef = useRef(true);\n\n /**\n * `silent` skips the isLoading flip for the refetch that follows a save: a page\n * written as `if (isLoading) return <Spinner/>` would otherwise unmount its own\n * form mid-save, losing focus and any uncommitted input. isSaving already covers\n * that window.\n */\n const load = useCallback(\n async ({ silent }: { silent?: boolean } = {}) => {\n const requestId = ++requestIdRef.current;\n if (!silent) setIsLoading(true);\n try {\n const loaded = await clientRef.current.get<T>(path);\n if (requestId !== requestIdRef.current) return;\n setSettings(loaded);\n setError(undefined);\n } catch (err) {\n if (requestId !== requestIdRef.current) return;\n setError(err);\n } finally {\n // Clearing is NOT conditional on `silent`: a save that races the very first\n // GET supersedes it, so the initial load can no longer clear the flag it\n // set — only the request that actually settles last can.\n if (requestId === requestIdRef.current) setIsLoading(false);\n }\n },\n [path],\n );\n\n useEffect(() => {\n isMountedRef.current = true;\n void load();\n return () => {\n isMountedRef.current = false;\n requestIdRef.current += 1;\n };\n }, [load]);\n\n const save = useCallback(\n async (patch: Partial<T>) => {\n setIsSaving(true);\n setSaveError(undefined);\n try {\n await clientRef.current.put<unknown>(path, patch);\n await load({ silent: true });\n } catch (err) {\n if (isMountedRef.current) setSaveError(err);\n } finally {\n if (isMountedRef.current) setIsSaving(false);\n }\n },\n [path, load],\n );\n\n return { settings, isLoading, error, save, isSaving, saveError };\n}\n","/**\n * Browser helpers for app pages.\n *\n * App bundles get react, react-dom and this SDK from the shell's import map and\n * bundle everything else themselves — so without these here, every app would\n * reimplement clipboard handling and CSV escaping, and get the edge cases wrong\n * in its own way.\n */\n\n/**\n * Copy text to the clipboard.\n *\n * Returns `false` instead of throwing when the clipboard is unavailable (non\n * secure context, permission refused) so the caller can render inline feedback.\n * No `document.execCommand('copy')` fallback: it is deprecated, and the shell\n * only ever runs on https or localhost, both secure contexts.\n */\nexport async function copyToClipboard(text: string): Promise<boolean> {\n if (!navigator?.clipboard || !window.isSecureContext) return false;\n try {\n await navigator.clipboard.writeText(text);\n return true;\n } catch {\n return false;\n }\n}\n\n/** Trigger a browser download of a Blob via a throwaway object URL + `<a>` click. */\nexport function downloadBlob(blob: Blob, filename: string): void {\n const url = URL.createObjectURL(blob);\n const a = document.createElement('a');\n a.href = url;\n a.download = filename;\n document.body.appendChild(a);\n a.click();\n a.remove();\n URL.revokeObjectURL(url);\n}\n\n/** Escape one CSV field per RFC 4180: quote it, and double any embedded quote,\n * whenever it contains a comma, a quote, or a line break. */\nfunction escapeCsvField(value: string): string {\n return /[\",\\r\\n]/.test(value) ? `\"${value.replace(/\"/g, '\"\"')}\"` : value;\n}\n\n/** Serialize rows (header included) into an RFC 4180 CSV string. */\nexport function toCsv(rows: string[][]): string {\n return rows.map((row) => row.map(escapeCsvField).join(',')).join('\\r\\n');\n}\n\n/** UTF-8 byte order mark. */\nconst BOM = '\\uFEFF';\n\n/**\n * Serialize + download in one call.\n *\n * The BOM is the whole reason this helper exists: without it Excel on Windows\n * reads the file as latin-1 and mangles every accented character.\n */\nexport function downloadCsv(rows: string[][], filename: string): void {\n const blob = new Blob([`${BOM}${toCsv(rows)}`], { type: 'text/csv;charset=utf-8' });\n downloadBlob(blob, filename);\n}\n","/**\n * Design system components exported by @apotech-os/ui-sdk.\n *\n * These are minimal self-contained copies of the shell's component library.\n * They use the same Tailwind utility classes as the shell — Tailwind classes\n * are plain strings and work without any build step when the shell's stylesheet\n * is loaded (which it is, since these pages run inside the shell).\n *\n * Strategy note:\n * - Not imported from apps/web (would create a circular dep pkg → app).\n * - Copied/adapted here to keep the SDK self-contained and publishable.\n * - The exhaustive component inventory is tracked in #75.\n */\n\nimport { type VariantProps, cva } from 'class-variance-authority';\nimport * as React from 'react';\nimport { cn } from './cn';\nimport { copyToClipboard } from './utils';\n\n// ---------------------------------------------------------------------------\n// Button\n// ---------------------------------------------------------------------------\n\nconst buttonVariants = cva(\n 'inline-flex cursor-pointer items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-50',\n {\n variants: {\n variant: {\n default: 'bg-primary text-primary-foreground hover:bg-primary/90',\n secondary: 'bg-secondary text-secondary-foreground hover:bg-secondary/80',\n outline: 'border border-input bg-background hover:bg-accent hover:text-accent-foreground',\n ghost: 'hover:bg-accent hover:text-accent-foreground',\n destructive: 'bg-destructive text-white hover:bg-destructive/90',\n },\n size: {\n default: 'h-9 px-4 py-2',\n sm: 'h-8 rounded-md px-3 text-xs',\n lg: 'h-10 rounded-md px-6',\n icon: 'h-9 w-9',\n },\n },\n defaultVariants: { variant: 'default', size: 'default' },\n },\n);\n\nexport interface ButtonProps\n extends React.ButtonHTMLAttributes<HTMLButtonElement>, VariantProps<typeof buttonVariants> {}\n\nexport const Button = React.forwardRef<HTMLButtonElement, ButtonProps>(\n ({ className, variant, size, ...props }, ref) => (\n <button ref={ref} className={cn(buttonVariants({ variant, size, className }))} {...props} />\n ),\n);\nButton.displayName = 'Button';\n\n// ---------------------------------------------------------------------------\n// Badge\n// ---------------------------------------------------------------------------\n\nconst badgeVariants = cva(\n 'inline-flex items-center gap-1.5 rounded-full border px-2 py-0.5 text-xs font-medium whitespace-nowrap',\n {\n variants: {\n variant: {\n neutral: 'border-border bg-muted text-muted-foreground',\n brand: 'border-primary/20 bg-primary/10 text-primary',\n success: 'border-status-success/25 bg-status-success/10 text-status-success',\n warning: 'border-status-pending/30 bg-status-pending/10 text-status-pending',\n danger: 'border-status-blocked/25 bg-status-blocked/10 text-status-blocked',\n info: 'border-status-info/25 bg-status-info/10 text-status-info',\n outline: 'border-border bg-transparent text-muted-foreground',\n },\n },\n defaultVariants: { variant: 'neutral' },\n },\n);\n\nexport interface BadgeProps\n extends React.HTMLAttributes<HTMLSpanElement>, VariantProps<typeof badgeVariants> {\n dot?: boolean;\n}\n\nexport function Badge({ className, variant, dot, children, ...props }: BadgeProps) {\n return (\n <span className={cn(badgeVariants({ variant }), className)} {...props}>\n {dot && <span className=\"size-1.5 rounded-full bg-current\" />}\n {children}\n </span>\n );\n}\n\n// ---------------------------------------------------------------------------\n// Card\n// ---------------------------------------------------------------------------\n\nexport function Card({ className, ...props }: React.HTMLAttributes<HTMLDivElement>) {\n return (\n <div\n className={cn('rounded-xl border bg-card text-card-foreground shadow-sm', className)}\n {...props}\n />\n );\n}\n\nexport function CardHeader({ className, ...props }: React.HTMLAttributes<HTMLDivElement>) {\n return <div className={cn('flex flex-col space-y-1.5 p-6', className)} {...props} />;\n}\n\nexport function CardTitle({ className, ...props }: React.HTMLAttributes<HTMLHeadingElement>) {\n return (\n <h3 className={cn('text-lg font-semibold leading-none tracking-tight', className)} {...props} />\n );\n}\n\nexport function CardContent({ className, ...props }: React.HTMLAttributes<HTMLDivElement>) {\n return <div className={cn('p-6 pt-0', className)} {...props} />;\n}\n\n// ---------------------------------------------------------------------------\n// Input\n// ---------------------------------------------------------------------------\n\nexport const Input = React.forwardRef<\n HTMLInputElement,\n React.InputHTMLAttributes<HTMLInputElement>\n>(({ className, type, ...props }, ref) => (\n <input\n type={type}\n className={cn(\n 'flex h-9 w-full rounded-md border border-input bg-transparent px-3 py-1 text-sm shadow-sm transition-colors file:border-0 file:bg-transparent file:text-sm file:font-medium placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:cursor-not-allowed disabled:opacity-50',\n className,\n )}\n ref={ref}\n {...props}\n />\n));\nInput.displayName = 'Input';\n\n// ---------------------------------------------------------------------------\n// Table\n// ---------------------------------------------------------------------------\n\nexport function Table({ className, ...props }: React.HTMLAttributes<HTMLTableElement>) {\n return <table className={cn('w-full text-sm', className)} {...props} />;\n}\n\nexport function TableHeader({\n className,\n ...props\n}: React.HTMLAttributes<HTMLTableSectionElement>) {\n return <thead className={cn('[&_tr]:border-b', className)} {...props} />;\n}\n\nexport function TableBody({ className, ...props }: React.HTMLAttributes<HTMLTableSectionElement>) {\n return <tbody className={cn('[&_tr:last-child]:border-0', className)} {...props} />;\n}\n\nexport function TableRow({ className, ...props }: React.HTMLAttributes<HTMLTableRowElement>) {\n return (\n <tr\n className={cn(\n 'border-b transition-colors hover:bg-muted/50 data-[state=selected]:bg-muted',\n className,\n )}\n {...props}\n />\n );\n}\n\nexport function TableHead({ className, ...props }: React.ThHTMLAttributes<HTMLTableCellElement>) {\n return (\n <th\n className={cn(\n 'h-10 px-4 text-left align-middle text-xs font-medium text-muted-foreground',\n className,\n )}\n {...props}\n />\n );\n}\n\nexport function TableCell({ className, ...props }: React.TdHTMLAttributes<HTMLTableCellElement>) {\n return <td className={cn('p-4 align-middle', className)} {...props} />;\n}\n\n// ---------------------------------------------------------------------------\n// Select\n// ---------------------------------------------------------------------------\n\nexport interface SelectProps extends React.SelectHTMLAttributes<HTMLSelectElement> {}\n\nexport const Select = React.forwardRef<HTMLSelectElement, SelectProps>(\n ({ className, children, ...props }, ref) => (\n <select\n ref={ref}\n className={cn(\n 'flex h-9 w-full rounded-md border border-input bg-transparent px-3 py-1 text-sm shadow-sm transition-colors focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:cursor-not-allowed disabled:opacity-50',\n className,\n )}\n {...props}\n >\n {children}\n </select>\n ),\n);\nSelect.displayName = 'Select';\n\n// ---------------------------------------------------------------------------\n// Tabs\n// ---------------------------------------------------------------------------\n\ninterface TabsContextValue {\n value: string;\n setValue: (v: string) => void;\n}\n\nconst TabsContext = React.createContext<TabsContextValue | null>(null);\n\nfunction useTabsContext(): TabsContextValue {\n const ctx = React.useContext(TabsContext);\n if (!ctx) throw new Error('Tabs sub-component must be used within <Tabs>');\n return ctx;\n}\n\nexport interface TabsProps {\n defaultValue?: string;\n value?: string;\n onValueChange?: (v: string) => void;\n className?: string;\n children: React.ReactNode;\n}\n\nexport function Tabs({ defaultValue, value, onValueChange, className, children }: TabsProps) {\n const [internal, setInternal] = React.useState(defaultValue ?? '');\n const current = value ?? internal;\n const setValue = (v: string) => {\n setInternal(v);\n onValueChange?.(v);\n };\n return (\n <TabsContext.Provider value={{ value: current, setValue }}>\n <div className={className}>{children}</div>\n </TabsContext.Provider>\n );\n}\n\nexport function TabsList({\n className,\n children,\n}: {\n className?: string;\n children: React.ReactNode;\n}) {\n return (\n <div className={cn('inline-flex items-center gap-1 rounded-lg bg-muted p-1', className)}>\n {children}\n </div>\n );\n}\n\nexport function TabsTrigger({\n value,\n className,\n children,\n}: {\n value: string;\n className?: string;\n children: React.ReactNode;\n}) {\n const { value: current, setValue } = useTabsContext();\n const active = current === value;\n return (\n <button\n type=\"button\"\n onClick={() => setValue(value)}\n className={cn(\n 'rounded-md px-3 py-1.5 text-sm font-medium transition-colors',\n active\n ? 'bg-card text-foreground shadow-sm'\n : 'text-muted-foreground hover:text-foreground',\n className,\n )}\n >\n {children}\n </button>\n );\n}\n\nexport function TabsContent({\n value,\n className,\n children,\n}: {\n value: string;\n className?: string;\n children: React.ReactNode;\n}) {\n const { value: current } = useTabsContext();\n if (current !== value) return null;\n return <div className={className}>{children}</div>;\n}\n\n// ---------------------------------------------------------------------------\n// Modal (controlled, no Radix)\n// ---------------------------------------------------------------------------\n\nexport interface ModalProps {\n open: boolean;\n onClose: () => void;\n title?: React.ReactNode;\n children: React.ReactNode;\n className?: string;\n}\n\nexport function Modal({ open, onClose, title, children, className }: ModalProps) {\n if (!open) return null;\n return (\n <div className=\"fixed inset-0 z-50 flex items-center justify-center p-4\">\n <button\n type=\"button\"\n aria-label=\"Close\"\n className=\"absolute inset-0 cursor-default bg-foreground/40\"\n onClick={onClose}\n />\n <div\n role=\"dialog\"\n aria-modal\n className={cn(\n 'relative z-10 w-full max-w-md rounded-xl border bg-card p-5 shadow-lg',\n className,\n )}\n >\n {title && <h2 className=\"mb-3 text-base font-semibold\">{title}</h2>}\n {children}\n </div>\n </div>\n );\n}\n\n// ---------------------------------------------------------------------------\n// Spinner\n// ---------------------------------------------------------------------------\n\nexport interface SpinnerProps {\n className?: string;\n size?: 'sm' | 'md' | 'lg';\n}\n\nconst spinnerSizes = { sm: 'size-4', md: 'size-6', lg: 'size-8' };\n\nexport function Spinner({ className, size = 'md' }: SpinnerProps) {\n return (\n <svg\n className={cn('animate-spin text-muted-foreground', spinnerSizes[size], className)}\n xmlns=\"http://www.w3.org/2000/svg\"\n fill=\"none\"\n viewBox=\"0 0 24 24\"\n aria-label=\"Loading\"\n role=\"status\"\n >\n <circle className=\"opacity-25\" cx=\"12\" cy=\"12\" r=\"10\" stroke=\"currentColor\" strokeWidth=\"4\" />\n <path\n className=\"opacity-75\"\n fill=\"currentColor\"\n d=\"M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4z\"\n />\n </svg>\n );\n}\n\n// ---------------------------------------------------------------------------\n// Link\n// ---------------------------------------------------------------------------\n\nexport interface LinkProps extends React.AnchorHTMLAttributes<HTMLAnchorElement> {\n variant?: 'default' | 'muted';\n}\n\nexport const Link = React.forwardRef<HTMLAnchorElement, LinkProps>(\n ({ className, variant = 'default', ...props }, ref) => (\n <a\n ref={ref}\n className={cn(\n 'underline-offset-4 hover:underline focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring',\n variant === 'default' ? 'text-primary' : 'text-muted-foreground',\n className,\n )}\n {...props}\n />\n ),\n);\nLink.displayName = 'Link';\n\n// ---------------------------------------------------------------------------\n// Switch\n// ---------------------------------------------------------------------------\n\nexport interface SwitchProps {\n checked?: boolean;\n onCheckedChange?: (checked: boolean) => void;\n disabled?: boolean;\n className?: string;\n 'aria-label'?: string;\n}\n\nexport function Switch({\n checked = false,\n onCheckedChange,\n disabled,\n className,\n ...props\n}: SwitchProps) {\n return (\n <button\n type=\"button\"\n role=\"switch\"\n aria-checked={checked}\n disabled={disabled}\n onClick={() => onCheckedChange?.(!checked)}\n className={cn(\n 'relative inline-flex h-5 w-9 shrink-0 cursor-pointer items-center rounded-full transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring disabled:cursor-not-allowed disabled:opacity-50',\n checked ? 'bg-primary' : 'bg-input',\n className,\n )}\n {...props}\n >\n <span\n className={cn(\n 'inline-block size-4 transform rounded-full bg-white shadow transition-transform',\n checked ? 'translate-x-4' : 'translate-x-0.5',\n )}\n />\n </button>\n );\n}\n\n// ---------------------------------------------------------------------------\n// DateRangePicker\n// ---------------------------------------------------------------------------\n\nexport interface DateRange {\n from: string;\n to: string;\n}\n\nexport interface DateRangePickerProps {\n value: DateRange;\n onChange: (range: DateRange) => void;\n className?: string;\n disabled?: boolean;\n}\n\n/** Minimal controlled date-range picker using two native date inputs. */\nexport function DateRangePicker({ value, onChange, className, disabled }: DateRangePickerProps) {\n return (\n <div className={cn('flex items-center gap-2', className)}>\n <input\n type=\"date\"\n disabled={disabled}\n value={value.from}\n max={value.to || undefined}\n onChange={(e) => onChange({ ...value, from: e.target.value })}\n className=\"flex h-9 rounded-md border border-input bg-transparent px-3 py-1 text-sm shadow-sm transition-colors focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:cursor-not-allowed disabled:opacity-50\"\n />\n <span className=\"text-muted-foreground text-sm\">→</span>\n <input\n type=\"date\"\n disabled={disabled}\n value={value.to}\n min={value.from || undefined}\n onChange={(e) => onChange({ ...value, to: e.target.value })}\n className=\"flex h-9 rounded-md border border-input bg-transparent px-3 py-1 text-sm shadow-sm transition-colors focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:cursor-not-allowed disabled:opacity-50\"\n />\n </div>\n );\n}\n\n// ---------------------------------------------------------------------------\n// Icons\n//\n// Inline SVGs rather than a lucide-react dependency: the SDK is loaded through\n// the shell's import map as a single vendor chunk, so a dependency here inflates\n// every app page. Same precedent as Spinner above.\n// ---------------------------------------------------------------------------\n\nfunction IconX({ className }: { className?: string }) {\n return (\n <svg\n className={className}\n xmlns=\"http://www.w3.org/2000/svg\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"2\"\n strokeLinecap=\"round\"\n aria-hidden=\"true\"\n >\n <path d=\"M18 6 6 18M6 6l12 12\" />\n </svg>\n );\n}\n\nfunction IconCopy({ className }: { className?: string }) {\n return (\n <svg\n className={className}\n xmlns=\"http://www.w3.org/2000/svg\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"2\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n aria-hidden=\"true\"\n >\n <rect width=\"14\" height=\"14\" x=\"8\" y=\"8\" rx=\"2\" ry=\"2\" />\n <path d=\"M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2\" />\n </svg>\n );\n}\n\nfunction IconCheck({ className }: { className?: string }) {\n return (\n <svg\n className={className}\n xmlns=\"http://www.w3.org/2000/svg\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"2\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n aria-hidden=\"true\"\n >\n <path d=\"M20 6 9 17l-5-5\" />\n </svg>\n );\n}\n\n// ---------------------------------------------------------------------------\n// Textarea\n// ---------------------------------------------------------------------------\n\nexport type TextareaProps = React.TextareaHTMLAttributes<HTMLTextAreaElement>;\n\nexport const Textarea = React.forwardRef<HTMLTextAreaElement, TextareaProps>(\n function Textarea({ className, ...props }, ref) {\n return (\n <textarea\n ref={ref}\n className={cn(\n 'flex min-h-20 w-full rounded-md border border-input bg-transparent px-3 py-2 text-sm shadow-sm transition-colors placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:cursor-not-allowed disabled:opacity-50',\n className,\n )}\n {...props}\n />\n );\n },\n);\n\n// ---------------------------------------------------------------------------\n// Checkbox\n// ---------------------------------------------------------------------------\n\nexport interface CheckboxProps\n extends Omit<React.InputHTMLAttributes<HTMLInputElement>, 'type' | 'onChange'> {\n checked?: boolean;\n /** Preferred over onChange — receives the boolean directly. */\n onCheckedChange?: (checked: boolean) => void;\n label?: React.ReactNode;\n}\n\nexport const Checkbox = React.forwardRef<HTMLInputElement, CheckboxProps>(\n function Checkbox({ className, label, onCheckedChange, ...props }, ref) {\n const input = (\n <input\n ref={ref}\n type=\"checkbox\"\n className={cn(\n 'size-4 shrink-0 cursor-pointer rounded border-input accent-primary disabled:cursor-not-allowed disabled:opacity-50',\n className,\n )}\n onChange={(e) => onCheckedChange?.(e.target.checked)}\n {...props}\n />\n );\n if (!label) return input;\n return (\n <label className=\"inline-flex cursor-pointer items-center gap-2 text-sm\">\n {input}\n <span>{label}</span>\n </label>\n );\n },\n);\n\n// ---------------------------------------------------------------------------\n// SidePanel\n// ---------------------------------------------------------------------------\n\nexport interface SidePanelProps {\n open: boolean;\n onClose: () => void;\n title?: React.ReactNode;\n description?: React.ReactNode;\n children: React.ReactNode;\n className?: string;\n}\n\n/**\n * Blocking slide-over — reach for it when a task has more fields than a `Modal`\n * can show without an inner scrollbar. Full height, so the body scrolls once and\n * a footer can stay pinned; `Modal` centres a box and does no height management.\n *\n * Children are laid out in a flex column filling the panel: put the scrollable\n * region in a `min-h-0 flex-1 overflow-y-auto` child and the footer after it.\n *\n * NOTE: no focus management. Autofocus the primary action yourself.\n */\nexport function SidePanel({\n open,\n onClose,\n title,\n description,\n children,\n className,\n}: SidePanelProps) {\n // Escape closes. A panel that covers the viewport makes a missing keyboard\n // exit far more noticeable than it is on a centred Modal.\n React.useEffect(() => {\n if (!open) return;\n const onKeyDown = (e: KeyboardEvent) => {\n if (e.key === 'Escape') onClose();\n };\n window.addEventListener('keydown', onKeyDown);\n return () => window.removeEventListener('keydown', onKeyDown);\n }, [open, onClose]);\n\n if (!open) return null;\n return (\n <div className=\"fixed inset-0 z-50\">\n <button\n type=\"button\"\n aria-label=\"Fermer\"\n className=\"absolute inset-0 cursor-default bg-foreground/40\"\n onClick={onClose}\n />\n <aside\n role=\"dialog\"\n aria-modal\n className={cn(\n 'absolute inset-y-0 right-0 flex w-full max-w-lg flex-col border-l bg-card shadow-xl',\n className,\n )}\n >\n <header className=\"flex shrink-0 items-start gap-3 border-b px-5 py-4\">\n <div className=\"min-w-0 flex-1\">\n {title && <h2 className=\"text-base font-semibold\">{title}</h2>}\n {description && <p className=\"mt-0.5 text-xs text-muted-foreground\">{description}</p>}\n </div>\n <button\n type=\"button\"\n aria-label=\"Fermer\"\n className=\"-mr-1 shrink-0 rounded-md p-1 text-muted-foreground hover:bg-accent hover:text-foreground\"\n onClick={onClose}\n >\n <IconX className=\"size-4\" />\n </button>\n </header>\n <div className=\"flex min-h-0 flex-1 flex-col px-5 py-4\">{children}</div>\n </aside>\n </div>\n );\n}\n\n// ---------------------------------------------------------------------------\n// CopyButton\n// ---------------------------------------------------------------------------\n\nexport interface CopyButtonProps {\n value: string;\n label?: string;\n copiedLabel?: string;\n variant?: ButtonProps['variant'];\n size?: ButtonProps['size'];\n className?: string;\n}\n\n/** How long the confirmation stays up before reverting. */\nconst COPY_FEEDBACK_MS = 2000;\n\n/**\n * Copy-to-clipboard button with inline feedback. On failure it says so rather\n * than silently doing nothing — keep the copyable text selectable so manual\n * copy stays the fallback.\n */\nexport function CopyButton({\n value,\n label = 'Copier',\n copiedLabel = 'Copié',\n variant = 'outline',\n size = 'sm',\n className,\n}: CopyButtonProps) {\n const [state, setState] = React.useState<'idle' | 'copied' | 'error'>('idle');\n const timeout = React.useRef<ReturnType<typeof setTimeout> | undefined>(undefined);\n\n // Held in a ref and cleared on unmount: the panel can close mid-feedback.\n React.useEffect(() => () => clearTimeout(timeout.current), []);\n\n async function copy() {\n const ok = await copyToClipboard(value);\n setState(ok ? 'copied' : 'error');\n clearTimeout(timeout.current);\n timeout.current = setTimeout(() => setState('idle'), COPY_FEEDBACK_MS);\n }\n\n return (\n <Button\n type=\"button\"\n variant={variant}\n size={size}\n className={className}\n onClick={() => void copy()}\n >\n {state === 'copied' ? (\n <IconCheck className=\"size-3.5\" />\n ) : (\n <IconCopy className=\"size-3.5\" />\n )}\n <span aria-live=\"polite\" className={state === 'error' ? 'text-destructive' : undefined}>\n {state === 'copied' ? copiedLabel : state === 'error' ? 'Copie impossible' : label}\n </span>\n </Button>\n );\n}\n\n// ---------------------------------------------------------------------------\n// Popover\n// ---------------------------------------------------------------------------\n\nexport interface PopoverProps {\n open: boolean;\n onOpenChange: (open: boolean) => void;\n trigger: React.ReactNode;\n children: React.ReactNode;\n align?: 'start' | 'end';\n className?: string;\n}\n\n/** Anchored panel. Controlled — the caller owns `open`. Closes on outside click\n * and Escape, which is what a filter pill needs and a Modal is too heavy for. */\nexport function Popover({\n open,\n onOpenChange,\n trigger,\n children,\n align = 'start',\n className,\n}: PopoverProps) {\n const root = React.useRef<HTMLDivElement>(null);\n\n React.useEffect(() => {\n if (!open) return;\n const onPointerDown = (e: MouseEvent) => {\n if (!root.current?.contains(e.target as Node)) onOpenChange(false);\n };\n const onKeyDown = (e: KeyboardEvent) => {\n if (e.key === 'Escape') onOpenChange(false);\n };\n document.addEventListener('mousedown', onPointerDown);\n document.addEventListener('keydown', onKeyDown);\n return () => {\n document.removeEventListener('mousedown', onPointerDown);\n document.removeEventListener('keydown', onKeyDown);\n };\n }, [open, onOpenChange]);\n\n return (\n <div ref={root} className=\"relative inline-block\">\n <button type=\"button\" aria-expanded={open} onClick={() => onOpenChange(!open)}>\n {trigger}\n </button>\n {open && (\n <div\n className={cn(\n 'absolute z-40 mt-1 min-w-48 rounded-md border bg-card p-2 shadow-lg',\n align === 'end' ? 'right-0' : 'left-0',\n className,\n )}\n >\n {children}\n </div>\n )}\n </div>\n );\n}\n\n// ---------------------------------------------------------------------------\n// DropdownMenu\n// ---------------------------------------------------------------------------\n\nexport interface DropdownMenuItem {\n label: React.ReactNode;\n onSelect: () => void;\n disabled?: boolean;\n destructive?: boolean;\n}\n\nexport interface DropdownMenuProps {\n trigger: React.ReactNode;\n items: DropdownMenuItem[];\n align?: 'start' | 'end';\n className?: string;\n}\n\n/** Uncontrolled menu built on Popover. Selecting an item closes it. */\nexport function DropdownMenu({ trigger, items, align = 'end', className }: DropdownMenuProps) {\n const [open, setOpen] = React.useState(false);\n return (\n <Popover\n open={open}\n onOpenChange={setOpen}\n trigger={trigger}\n align={align}\n className={cn('p-1', className)}\n >\n <div role=\"menu\" className=\"flex flex-col\">\n {items.map((item, i) => (\n <button\n key={i}\n type=\"button\"\n role=\"menuitem\"\n disabled={item.disabled}\n className={cn(\n 'cursor-pointer rounded px-2 py-1.5 text-left text-sm hover:bg-accent disabled:pointer-events-none disabled:opacity-50',\n item.destructive && 'text-destructive',\n )}\n onClick={() => {\n setOpen(false);\n item.onSelect();\n }}\n >\n {item.label}\n </button>\n ))}\n </div>\n </Popover>\n );\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/cn.ts","../src/hooks.ts","../src/utils.ts","../src/components.tsx"],"names":["twMerge","clsx","createContext","useContext","useState","useRef","useCallback","useEffect","cva","React","jsx","jsxs","Textarea","Checkbox"],"mappings":"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","file":"index.cjs","sourcesContent":["import { type ClassValue, clsx } from 'clsx';\nimport { twMerge } from 'tailwind-merge';\n\nexport function cn(...inputs: ClassValue[]): string {\n return twMerge(clsx(inputs));\n}\n","/**\n * Runtime hooks provided by the shell via @apotech-os/ui-sdk.\n *\n * These hooks are implemented by the shell and injected at runtime via the\n * import map. App pages call them without knowing the shell internals.\n *\n * The default implementations throw if called outside of the shell context\n * (which should never happen in production — the shell always provides them\n * via the import map before mounting an app page).\n */\n\nimport { useContext, createContext, useCallback, useEffect, useRef, useState } from 'react';\n// `import type` only: ui-sdk has no runtime dependency on app-kit, so this must\n// not appear in the built dist/index.js (verified — see error-codes.ts).\nimport type { AppErrorCode } from '@apotech-os/app-kit';\n\n// ---------------------------------------------------------------------------\n// AppContext\n// ---------------------------------------------------------------------------\n\nexport interface AppContextValue {\n /** The slug of the installed app owning this page. */\n appSlug: string;\n /** The page path within the app (e.g. 'attribution'). */\n pagePath: string;\n /** The active space id, when applicable. */\n spaceId?: string;\n /**\n * The current user's grant role on this app context, when the shell knows it.\n * Settings pages use it to render read-only fields below ADMIN instead of\n * letting the user discover the 403 at save time.\n */\n role?: 'VIEWER' | 'EDITOR' | 'ADMIN';\n}\n\nconst AppContextInternalCtx = createContext<AppContextValue | null>(null);\n\nexport const AppContextProvider = AppContextInternalCtx.Provider;\n\n/** Returns context info for the current app page (appSlug, pagePath, spaceId). */\nexport function useAppContext(): AppContextValue {\n const ctx = useContext(AppContextInternalCtx);\n if (!ctx) throw new Error('useAppContext must be used inside an app page mounted by the shell');\n return ctx;\n}\n\n// ---------------------------------------------------------------------------\n// AppApi\n// ---------------------------------------------------------------------------\n\nexport interface AppApiClient {\n /**\n * Perform a GET request to a platform-data endpoint.\n * The session cookie is forwarded automatically (same-origin, withCredentials).\n */\n get<T>(path: string, params?: Record<string, string>): Promise<T>;\n /**\n * Perform a POST request to a platform-data endpoint.\n */\n post<T>(path: string, body?: unknown): Promise<T>;\n /**\n * Perform a PUT request to a platform-data endpoint (e.g. write app settings).\n */\n put<T>(path: string, body?: unknown): Promise<T>;\n /**\n * Perform a PATCH request to a platform-data endpoint (e.g. update a record).\n */\n patch<T>(path: string, body?: unknown): Promise<T>;\n /**\n * Perform a DELETE request to a platform-data endpoint (e.g. delete a record).\n */\n delete<T>(path: string): Promise<T>;\n /**\n * Run one of this app's `uiInvoke` functions and get its return value back.\n *\n * This is the ONLY way a page can reach an integration: the action endpoint\n * requires an app token and refuses a browser session. The platform mints the\n * token server-side and runs the handler in-process.\n *\n * The function must be declared `trigger: { type: 'uiInvoke' }` in the\n * manifest, and the caller must hold its `minRole` (default EDITOR).\n *\n * Pass `idempotencyKey` for anything that must not run twice on a double\n * click — a concurrent duplicate is rejected with 409 INVOCATION_IN_FLIGHT.\n *\n * Throws AppInvokeError. `code === 'FUNCTION_REJECTED'` carries an app-authored\n * message that is safe to show the user; every other failure is generic on\n * purpose (raw provider errors can leak tokens or PII).\n */\n invoke<TResult, TInput = Record<string, unknown>>(\n functionName: string,\n input?: TInput,\n opts?: { idempotencyKey?: string; signal?: AbortSignal },\n ): Promise<TResult>;\n}\n\n/** Thrown by AppApiClient.invoke. */\nexport class AppInvokeError extends Error {\n constructor(\n readonly status: number,\n message: string,\n // `AppErrorCode | (string & {})` gives autocomplete on the known codes\n // while keeping any other string assignable — a server that returns an\n // unlisted `code` (or none) must not fail to compile against this type.\n readonly code?: AppErrorCode | (string & {}),\n readonly invocationId?: string,\n ) {\n super(message);\n this.name = 'AppInvokeError';\n }\n}\n\nconst AppApiCtx = createContext<AppApiClient | null>(null);\n\nexport const AppApiProvider = AppApiCtx.Provider;\n\n/**\n * Returns an API client scoped to the current user session.\n * Requests go to /api/data/* with the session cookie (RBAC applies server-side).\n */\nexport function useAppApi(): AppApiClient {\n const client = useContext(AppApiCtx);\n if (!client) throw new Error('useAppApi must be used inside an app page mounted by the shell');\n return client;\n}\n\n// ---------------------------------------------------------------------------\n// AppSettings\n// ---------------------------------------------------------------------------\n\n/**\n * Reads and writes this app's settings (GET/PUT /data/apps/:appSlug/settings).\n *\n * The app slug comes from the surrounding AppContext, so a settings page only\n * has to describe its form. Values are the ones the server merged with the\n * `settings.fields` defaults declared in the manifest.\n *\n * Reading requires VIEWER, writing requires ADMIN. `save` never throws: it\n * reports through `saveError`, which carries the raw failure (422\n * SETTINGS_VALIDATION_FAILED with its per-key errors, or 403) so the page can\n * map it back onto its fields. A failed save leaves `settings` untouched.\n */\nexport function useAppSettings<T = Record<string, unknown>>(): {\n settings: T | undefined;\n isLoading: boolean;\n error: unknown;\n save: (patch: Partial<T>) => Promise<void>;\n isSaving: boolean;\n saveError: unknown;\n} {\n const { appSlug } = useAppContext();\n const api = useAppApi();\n const path = `/data/apps/${appSlug}/settings`;\n\n const [settings, setSettings] = useState<T | undefined>(undefined);\n const [isLoading, setIsLoading] = useState(true);\n const [error, setError] = useState<unknown>(undefined);\n const [isSaving, setIsSaving] = useState(false);\n const [saveError, setSaveError] = useState<unknown>(undefined);\n\n // The shell rebuilds the client on every render, so it cannot be an effect\n // dependency without refetching in a loop.\n const clientRef = useRef(api);\n clientRef.current = api;\n // Bumped by every request and by unmount: a superseded or late response is\n // dropped instead of overwriting fresher state.\n const requestIdRef = useRef(0);\n const isMountedRef = useRef(true);\n\n /**\n * `silent` skips the isLoading flip for the refetch that follows a save: a page\n * written as `if (isLoading) return <Spinner/>` would otherwise unmount its own\n * form mid-save, losing focus and any uncommitted input. isSaving already covers\n * that window.\n */\n const load = useCallback(\n async ({ silent }: { silent?: boolean } = {}) => {\n const requestId = ++requestIdRef.current;\n if (!silent) setIsLoading(true);\n try {\n const loaded = await clientRef.current.get<T>(path);\n if (requestId !== requestIdRef.current) return;\n setSettings(loaded);\n setError(undefined);\n } catch (err) {\n if (requestId !== requestIdRef.current) return;\n setError(err);\n } finally {\n // Clearing is NOT conditional on `silent`: a save that races the very first\n // GET supersedes it, so the initial load can no longer clear the flag it\n // set — only the request that actually settles last can.\n if (requestId === requestIdRef.current) setIsLoading(false);\n }\n },\n [path],\n );\n\n useEffect(() => {\n isMountedRef.current = true;\n void load();\n return () => {\n isMountedRef.current = false;\n requestIdRef.current += 1;\n };\n }, [load]);\n\n const save = useCallback(\n async (patch: Partial<T>) => {\n setIsSaving(true);\n setSaveError(undefined);\n try {\n await clientRef.current.put<unknown>(path, patch);\n await load({ silent: true });\n } catch (err) {\n if (isMountedRef.current) setSaveError(err);\n } finally {\n if (isMountedRef.current) setIsSaving(false);\n }\n },\n [path, load],\n );\n\n return { settings, isLoading, error, save, isSaving, saveError };\n}\n","/**\n * Browser helpers for app pages.\n *\n * App bundles get react, react-dom and this SDK from the shell's import map and\n * bundle everything else themselves — so without these here, every app would\n * reimplement clipboard handling and CSV escaping, and get the edge cases wrong\n * in its own way.\n */\n\n/**\n * Copy text to the clipboard.\n *\n * Returns `false` instead of throwing when the clipboard is unavailable (non\n * secure context, permission refused) so the caller can render inline feedback.\n * No `document.execCommand('copy')` fallback: it is deprecated, and the shell\n * only ever runs on https or localhost, both secure contexts.\n */\nexport async function copyToClipboard(text: string): Promise<boolean> {\n if (!navigator?.clipboard || !window.isSecureContext) return false;\n try {\n await navigator.clipboard.writeText(text);\n return true;\n } catch {\n return false;\n }\n}\n\n/** Trigger a browser download of a Blob via a throwaway object URL + `<a>` click. */\nexport function downloadBlob(blob: Blob, filename: string): void {\n const url = URL.createObjectURL(blob);\n const a = document.createElement('a');\n a.href = url;\n a.download = filename;\n document.body.appendChild(a);\n a.click();\n a.remove();\n URL.revokeObjectURL(url);\n}\n\n/** Escape one CSV field per RFC 4180: quote it, and double any embedded quote,\n * whenever it contains a comma, a quote, or a line break. */\nfunction escapeCsvField(value: string): string {\n return /[\",\\r\\n]/.test(value) ? `\"${value.replace(/\"/g, '\"\"')}\"` : value;\n}\n\n/** Serialize rows (header included) into an RFC 4180 CSV string. */\nexport function toCsv(rows: string[][]): string {\n return rows.map((row) => row.map(escapeCsvField).join(',')).join('\\r\\n');\n}\n\n/** UTF-8 byte order mark. */\nconst BOM = '\\uFEFF';\n\n/**\n * Serialize + download in one call.\n *\n * The BOM is the whole reason this helper exists: without it Excel on Windows\n * reads the file as latin-1 and mangles every accented character.\n */\nexport function downloadCsv(rows: string[][], filename: string): void {\n const blob = new Blob([`${BOM}${toCsv(rows)}`], { type: 'text/csv;charset=utf-8' });\n downloadBlob(blob, filename);\n}\n","/**\n * Design system components exported by @apotech-os/ui-sdk.\n *\n * These are minimal self-contained copies of the shell's component library.\n * They use the same Tailwind utility classes as the shell — Tailwind classes\n * are plain strings and work without any build step when the shell's stylesheet\n * is loaded (which it is, since these pages run inside the shell).\n *\n * Strategy note:\n * - Not imported from apps/web (would create a circular dep pkg → app).\n * - Copied/adapted here to keep the SDK self-contained and publishable.\n * - The exhaustive component inventory is tracked in #75.\n */\n\nimport { type VariantProps, cva } from 'class-variance-authority';\nimport * as React from 'react';\nimport { cn } from './cn';\nimport { copyToClipboard } from './utils';\n\n// ---------------------------------------------------------------------------\n// Button\n// ---------------------------------------------------------------------------\n\nconst buttonVariants = cva(\n 'inline-flex cursor-pointer items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-50',\n {\n variants: {\n variant: {\n default: 'bg-primary text-primary-foreground hover:bg-primary/90',\n secondary: 'bg-secondary text-secondary-foreground hover:bg-secondary/80',\n outline: 'border border-input bg-background hover:bg-accent hover:text-accent-foreground',\n ghost: 'hover:bg-accent hover:text-accent-foreground',\n destructive: 'bg-destructive text-white hover:bg-destructive/90',\n },\n size: {\n default: 'h-9 px-4 py-2',\n sm: 'h-8 rounded-md px-3 text-xs',\n lg: 'h-10 rounded-md px-6',\n icon: 'h-9 w-9',\n },\n },\n defaultVariants: { variant: 'default', size: 'default' },\n },\n);\n\nexport interface ButtonProps\n extends React.ButtonHTMLAttributes<HTMLButtonElement>, VariantProps<typeof buttonVariants> {}\n\nexport const Button = React.forwardRef<HTMLButtonElement, ButtonProps>(\n ({ className, variant, size, ...props }, ref) => (\n <button ref={ref} className={cn(buttonVariants({ variant, size, className }))} {...props} />\n ),\n);\nButton.displayName = 'Button';\n\n// ---------------------------------------------------------------------------\n// Badge\n// ---------------------------------------------------------------------------\n\nconst badgeVariants = cva(\n 'inline-flex items-center gap-1.5 rounded-full border px-2 py-0.5 text-xs font-medium whitespace-nowrap',\n {\n variants: {\n variant: {\n neutral: 'border-border bg-muted text-muted-foreground',\n brand: 'border-primary/20 bg-primary/10 text-primary',\n success: 'border-status-success/25 bg-status-success/10 text-status-success',\n warning: 'border-status-pending/30 bg-status-pending/10 text-status-pending',\n danger: 'border-status-blocked/25 bg-status-blocked/10 text-status-blocked',\n info: 'border-status-info/25 bg-status-info/10 text-status-info',\n outline: 'border-border bg-transparent text-muted-foreground',\n },\n },\n defaultVariants: { variant: 'neutral' },\n },\n);\n\nexport interface BadgeProps\n extends React.HTMLAttributes<HTMLSpanElement>, VariantProps<typeof badgeVariants> {\n dot?: boolean;\n}\n\nexport function Badge({ className, variant, dot, children, ...props }: BadgeProps) {\n return (\n <span className={cn(badgeVariants({ variant }), className)} {...props}>\n {dot && <span className=\"size-1.5 rounded-full bg-current\" />}\n {children}\n </span>\n );\n}\n\n// ---------------------------------------------------------------------------\n// Card\n// ---------------------------------------------------------------------------\n\nexport function Card({ className, ...props }: React.HTMLAttributes<HTMLDivElement>) {\n return (\n <div\n className={cn('rounded-xl border bg-card text-card-foreground shadow-sm', className)}\n {...props}\n />\n );\n}\n\nexport function CardHeader({ className, ...props }: React.HTMLAttributes<HTMLDivElement>) {\n return <div className={cn('flex flex-col space-y-1.5 p-6', className)} {...props} />;\n}\n\nexport function CardTitle({ className, ...props }: React.HTMLAttributes<HTMLHeadingElement>) {\n return (\n <h3 className={cn('text-lg font-semibold leading-none tracking-tight', className)} {...props} />\n );\n}\n\nexport function CardContent({ className, ...props }: React.HTMLAttributes<HTMLDivElement>) {\n return <div className={cn('p-6 pt-0', className)} {...props} />;\n}\n\n// ---------------------------------------------------------------------------\n// Input\n// ---------------------------------------------------------------------------\n\nexport const Input = React.forwardRef<\n HTMLInputElement,\n React.InputHTMLAttributes<HTMLInputElement>\n>(({ className, type, ...props }, ref) => (\n <input\n type={type}\n className={cn(\n 'flex h-9 w-full rounded-md border border-input bg-transparent px-3 py-1 text-sm shadow-sm transition-colors file:border-0 file:bg-transparent file:text-sm file:font-medium placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:cursor-not-allowed disabled:opacity-50',\n className,\n )}\n ref={ref}\n {...props}\n />\n));\nInput.displayName = 'Input';\n\n// ---------------------------------------------------------------------------\n// Table\n// ---------------------------------------------------------------------------\n\nexport function Table({ className, ...props }: React.HTMLAttributes<HTMLTableElement>) {\n return <table className={cn('w-full text-sm', className)} {...props} />;\n}\n\nexport function TableHeader({\n className,\n ...props\n}: React.HTMLAttributes<HTMLTableSectionElement>) {\n return <thead className={cn('[&_tr]:border-b', className)} {...props} />;\n}\n\nexport function TableBody({ className, ...props }: React.HTMLAttributes<HTMLTableSectionElement>) {\n return <tbody className={cn('[&_tr:last-child]:border-0', className)} {...props} />;\n}\n\nexport function TableRow({ className, ...props }: React.HTMLAttributes<HTMLTableRowElement>) {\n return (\n <tr\n className={cn(\n 'border-b transition-colors hover:bg-muted/50 data-[state=selected]:bg-muted',\n className,\n )}\n {...props}\n />\n );\n}\n\nexport function TableHead({ className, ...props }: React.ThHTMLAttributes<HTMLTableCellElement>) {\n return (\n <th\n className={cn(\n 'h-10 px-4 text-left align-middle text-xs font-medium text-muted-foreground',\n className,\n )}\n {...props}\n />\n );\n}\n\nexport function TableCell({ className, ...props }: React.TdHTMLAttributes<HTMLTableCellElement>) {\n return <td className={cn('p-4 align-middle', className)} {...props} />;\n}\n\n// ---------------------------------------------------------------------------\n// Select\n// ---------------------------------------------------------------------------\n\nexport interface SelectProps extends React.SelectHTMLAttributes<HTMLSelectElement> {}\n\nexport const Select = React.forwardRef<HTMLSelectElement, SelectProps>(\n ({ className, children, ...props }, ref) => (\n <select\n ref={ref}\n className={cn(\n 'flex h-9 w-full rounded-md border border-input bg-transparent px-3 py-1 text-sm shadow-sm transition-colors focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:cursor-not-allowed disabled:opacity-50',\n className,\n )}\n {...props}\n >\n {children}\n </select>\n ),\n);\nSelect.displayName = 'Select';\n\n// ---------------------------------------------------------------------------\n// Tabs\n// ---------------------------------------------------------------------------\n\ninterface TabsContextValue {\n value: string;\n setValue: (v: string) => void;\n}\n\nconst TabsContext = React.createContext<TabsContextValue | null>(null);\n\nfunction useTabsContext(): TabsContextValue {\n const ctx = React.useContext(TabsContext);\n if (!ctx) throw new Error('Tabs sub-component must be used within <Tabs>');\n return ctx;\n}\n\nexport interface TabsProps {\n defaultValue?: string;\n value?: string;\n onValueChange?: (v: string) => void;\n className?: string;\n children: React.ReactNode;\n}\n\nexport function Tabs({ defaultValue, value, onValueChange, className, children }: TabsProps) {\n const [internal, setInternal] = React.useState(defaultValue ?? '');\n const current = value ?? internal;\n const setValue = (v: string) => {\n setInternal(v);\n onValueChange?.(v);\n };\n return (\n <TabsContext.Provider value={{ value: current, setValue }}>\n <div className={className}>{children}</div>\n </TabsContext.Provider>\n );\n}\n\nexport function TabsList({\n className,\n children,\n}: {\n className?: string;\n children: React.ReactNode;\n}) {\n return (\n <div className={cn('inline-flex items-center gap-1 rounded-lg bg-muted p-1', className)}>\n {children}\n </div>\n );\n}\n\nexport function TabsTrigger({\n value,\n className,\n children,\n}: {\n value: string;\n className?: string;\n children: React.ReactNode;\n}) {\n const { value: current, setValue } = useTabsContext();\n const active = current === value;\n return (\n <button\n type=\"button\"\n onClick={() => setValue(value)}\n className={cn(\n 'rounded-md px-3 py-1.5 text-sm font-medium transition-colors',\n active\n ? 'bg-card text-foreground shadow-sm'\n : 'text-muted-foreground hover:text-foreground',\n className,\n )}\n >\n {children}\n </button>\n );\n}\n\nexport function TabsContent({\n value,\n className,\n children,\n}: {\n value: string;\n className?: string;\n children: React.ReactNode;\n}) {\n const { value: current } = useTabsContext();\n if (current !== value) return null;\n return <div className={className}>{children}</div>;\n}\n\n// ---------------------------------------------------------------------------\n// Modal (controlled, no Radix)\n// ---------------------------------------------------------------------------\n\nexport interface ModalProps {\n open: boolean;\n onClose: () => void;\n title?: React.ReactNode;\n children: React.ReactNode;\n className?: string;\n}\n\nexport function Modal({ open, onClose, title, children, className }: ModalProps) {\n if (!open) return null;\n return (\n <div className=\"fixed inset-0 z-50 flex items-center justify-center p-4\">\n <button\n type=\"button\"\n aria-label=\"Close\"\n className=\"absolute inset-0 cursor-default bg-foreground/40\"\n onClick={onClose}\n />\n <div\n role=\"dialog\"\n aria-modal\n className={cn(\n 'relative z-10 w-full max-w-md rounded-xl border bg-card p-5 shadow-lg',\n className,\n )}\n >\n {title && <h2 className=\"mb-3 text-base font-semibold\">{title}</h2>}\n {children}\n </div>\n </div>\n );\n}\n\n// ---------------------------------------------------------------------------\n// Spinner\n// ---------------------------------------------------------------------------\n\nexport interface SpinnerProps {\n className?: string;\n size?: 'sm' | 'md' | 'lg';\n}\n\nconst spinnerSizes = { sm: 'size-4', md: 'size-6', lg: 'size-8' };\n\nexport function Spinner({ className, size = 'md' }: SpinnerProps) {\n return (\n <svg\n className={cn('animate-spin text-muted-foreground', spinnerSizes[size], className)}\n xmlns=\"http://www.w3.org/2000/svg\"\n fill=\"none\"\n viewBox=\"0 0 24 24\"\n aria-label=\"Loading\"\n role=\"status\"\n >\n <circle className=\"opacity-25\" cx=\"12\" cy=\"12\" r=\"10\" stroke=\"currentColor\" strokeWidth=\"4\" />\n <path\n className=\"opacity-75\"\n fill=\"currentColor\"\n d=\"M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4z\"\n />\n </svg>\n );\n}\n\n// ---------------------------------------------------------------------------\n// Link\n// ---------------------------------------------------------------------------\n\nexport interface LinkProps extends React.AnchorHTMLAttributes<HTMLAnchorElement> {\n variant?: 'default' | 'muted';\n}\n\nexport const Link = React.forwardRef<HTMLAnchorElement, LinkProps>(\n ({ className, variant = 'default', ...props }, ref) => (\n <a\n ref={ref}\n className={cn(\n 'underline-offset-4 hover:underline focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring',\n variant === 'default' ? 'text-primary' : 'text-muted-foreground',\n className,\n )}\n {...props}\n />\n ),\n);\nLink.displayName = 'Link';\n\n// ---------------------------------------------------------------------------\n// Switch\n// ---------------------------------------------------------------------------\n\nexport interface SwitchProps {\n checked?: boolean;\n onCheckedChange?: (checked: boolean) => void;\n disabled?: boolean;\n className?: string;\n 'aria-label'?: string;\n}\n\nexport function Switch({\n checked = false,\n onCheckedChange,\n disabled,\n className,\n ...props\n}: SwitchProps) {\n return (\n <button\n type=\"button\"\n role=\"switch\"\n aria-checked={checked}\n disabled={disabled}\n onClick={() => onCheckedChange?.(!checked)}\n className={cn(\n 'relative inline-flex h-5 w-9 shrink-0 cursor-pointer items-center rounded-full transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring disabled:cursor-not-allowed disabled:opacity-50',\n checked ? 'bg-primary' : 'bg-input',\n className,\n )}\n {...props}\n >\n <span\n className={cn(\n 'inline-block size-4 transform rounded-full bg-white shadow transition-transform',\n checked ? 'translate-x-4' : 'translate-x-0.5',\n )}\n />\n </button>\n );\n}\n\n// ---------------------------------------------------------------------------\n// DateRangePicker\n// ---------------------------------------------------------------------------\n\nexport interface DateRange {\n from: string;\n to: string;\n}\n\nexport interface DateRangePickerProps {\n value: DateRange;\n onChange: (range: DateRange) => void;\n className?: string;\n disabled?: boolean;\n}\n\n/** Minimal controlled date-range picker using two native date inputs. */\nexport function DateRangePicker({ value, onChange, className, disabled }: DateRangePickerProps) {\n return (\n <div className={cn('flex items-center gap-2', className)}>\n <input\n type=\"date\"\n disabled={disabled}\n value={value.from}\n max={value.to || undefined}\n onChange={(e) => onChange({ ...value, from: e.target.value })}\n className=\"flex h-9 rounded-md border border-input bg-transparent px-3 py-1 text-sm shadow-sm transition-colors focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:cursor-not-allowed disabled:opacity-50\"\n />\n <span className=\"text-muted-foreground text-sm\">→</span>\n <input\n type=\"date\"\n disabled={disabled}\n value={value.to}\n min={value.from || undefined}\n onChange={(e) => onChange({ ...value, to: e.target.value })}\n className=\"flex h-9 rounded-md border border-input bg-transparent px-3 py-1 text-sm shadow-sm transition-colors focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:cursor-not-allowed disabled:opacity-50\"\n />\n </div>\n );\n}\n\n// ---------------------------------------------------------------------------\n// Icons\n//\n// Inline SVGs rather than a lucide-react dependency: the SDK is loaded through\n// the shell's import map as a single vendor chunk, so a dependency here inflates\n// every app page. Same precedent as Spinner above.\n// ---------------------------------------------------------------------------\n\nfunction IconX({ className }: { className?: string }) {\n return (\n <svg\n className={className}\n xmlns=\"http://www.w3.org/2000/svg\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"2\"\n strokeLinecap=\"round\"\n aria-hidden=\"true\"\n >\n <path d=\"M18 6 6 18M6 6l12 12\" />\n </svg>\n );\n}\n\nfunction IconCopy({ className }: { className?: string }) {\n return (\n <svg\n className={className}\n xmlns=\"http://www.w3.org/2000/svg\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"2\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n aria-hidden=\"true\"\n >\n <rect width=\"14\" height=\"14\" x=\"8\" y=\"8\" rx=\"2\" ry=\"2\" />\n <path d=\"M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2\" />\n </svg>\n );\n}\n\nfunction IconCheck({ className }: { className?: string }) {\n return (\n <svg\n className={className}\n xmlns=\"http://www.w3.org/2000/svg\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"2\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n aria-hidden=\"true\"\n >\n <path d=\"M20 6 9 17l-5-5\" />\n </svg>\n );\n}\n\n// ---------------------------------------------------------------------------\n// Textarea\n// ---------------------------------------------------------------------------\n\nexport type TextareaProps = React.TextareaHTMLAttributes<HTMLTextAreaElement>;\n\nexport const Textarea = React.forwardRef<HTMLTextAreaElement, TextareaProps>(\n function Textarea({ className, ...props }, ref) {\n return (\n <textarea\n ref={ref}\n className={cn(\n 'flex min-h-20 w-full rounded-md border border-input bg-transparent px-3 py-2 text-sm shadow-sm transition-colors placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:cursor-not-allowed disabled:opacity-50',\n className,\n )}\n {...props}\n />\n );\n },\n);\n\n// ---------------------------------------------------------------------------\n// Checkbox\n// ---------------------------------------------------------------------------\n\nexport interface CheckboxProps\n extends Omit<React.InputHTMLAttributes<HTMLInputElement>, 'type' | 'onChange'> {\n checked?: boolean;\n /** Preferred over onChange — receives the boolean directly. */\n onCheckedChange?: (checked: boolean) => void;\n label?: React.ReactNode;\n}\n\nexport const Checkbox = React.forwardRef<HTMLInputElement, CheckboxProps>(\n function Checkbox({ className, label, onCheckedChange, ...props }, ref) {\n const input = (\n <input\n ref={ref}\n type=\"checkbox\"\n className={cn(\n 'size-4 shrink-0 cursor-pointer rounded border-input accent-primary disabled:cursor-not-allowed disabled:opacity-50',\n className,\n )}\n onChange={(e) => onCheckedChange?.(e.target.checked)}\n {...props}\n />\n );\n if (!label) return input;\n return (\n <label className=\"inline-flex cursor-pointer items-center gap-2 text-sm\">\n {input}\n <span>{label}</span>\n </label>\n );\n },\n);\n\n// ---------------------------------------------------------------------------\n// SidePanel\n// ---------------------------------------------------------------------------\n\nexport interface SidePanelProps {\n open: boolean;\n onClose: () => void;\n title?: React.ReactNode;\n description?: React.ReactNode;\n children: React.ReactNode;\n className?: string;\n}\n\n/**\n * Blocking slide-over — reach for it when a task has more fields than a `Modal`\n * can show without an inner scrollbar. Full height, so the body scrolls once and\n * a footer can stay pinned; `Modal` centres a box and does no height management.\n *\n * Children are laid out in a flex column filling the panel: put the scrollable\n * region in a `min-h-0 flex-1 overflow-y-auto` child and the footer after it.\n *\n * NOTE: no focus management. Autofocus the primary action yourself.\n */\nexport function SidePanel({\n open,\n onClose,\n title,\n description,\n children,\n className,\n}: SidePanelProps) {\n // Escape closes. A panel that covers the viewport makes a missing keyboard\n // exit far more noticeable than it is on a centred Modal.\n React.useEffect(() => {\n if (!open) return;\n const onKeyDown = (e: KeyboardEvent) => {\n if (e.key === 'Escape') onClose();\n };\n window.addEventListener('keydown', onKeyDown);\n return () => window.removeEventListener('keydown', onKeyDown);\n }, [open, onClose]);\n\n if (!open) return null;\n return (\n <div className=\"fixed inset-0 z-50\">\n <button\n type=\"button\"\n aria-label=\"Fermer\"\n className=\"absolute inset-0 cursor-default bg-foreground/40\"\n onClick={onClose}\n />\n <aside\n role=\"dialog\"\n aria-modal\n className={cn(\n 'absolute inset-y-0 right-0 flex w-full max-w-lg flex-col border-l bg-card shadow-xl',\n className,\n )}\n >\n <header className=\"flex shrink-0 items-start gap-3 border-b px-5 py-4\">\n <div className=\"min-w-0 flex-1\">\n {title && <h2 className=\"text-base font-semibold\">{title}</h2>}\n {description && <p className=\"mt-0.5 text-xs text-muted-foreground\">{description}</p>}\n </div>\n <button\n type=\"button\"\n aria-label=\"Fermer\"\n className=\"-mr-1 shrink-0 rounded-md p-1 text-muted-foreground hover:bg-accent hover:text-foreground\"\n onClick={onClose}\n >\n <IconX className=\"size-4\" />\n </button>\n </header>\n <div className=\"flex min-h-0 flex-1 flex-col px-5 py-4\">{children}</div>\n </aside>\n </div>\n );\n}\n\n// ---------------------------------------------------------------------------\n// CopyButton\n// ---------------------------------------------------------------------------\n\nexport interface CopyButtonProps {\n value: string;\n label?: string;\n copiedLabel?: string;\n variant?: ButtonProps['variant'];\n size?: ButtonProps['size'];\n className?: string;\n}\n\n/** How long the confirmation stays up before reverting. */\nconst COPY_FEEDBACK_MS = 2000;\n\n/**\n * Copy-to-clipboard button with inline feedback. On failure it says so rather\n * than silently doing nothing — keep the copyable text selectable so manual\n * copy stays the fallback.\n */\nexport function CopyButton({\n value,\n label = 'Copier',\n copiedLabel = 'Copié',\n variant = 'outline',\n size = 'sm',\n className,\n}: CopyButtonProps) {\n const [state, setState] = React.useState<'idle' | 'copied' | 'error'>('idle');\n const timeout = React.useRef<ReturnType<typeof setTimeout> | undefined>(undefined);\n\n // Held in a ref and cleared on unmount: the panel can close mid-feedback.\n React.useEffect(() => () => clearTimeout(timeout.current), []);\n\n async function copy() {\n const ok = await copyToClipboard(value);\n setState(ok ? 'copied' : 'error');\n clearTimeout(timeout.current);\n timeout.current = setTimeout(() => setState('idle'), COPY_FEEDBACK_MS);\n }\n\n return (\n <Button\n type=\"button\"\n variant={variant}\n size={size}\n className={className}\n onClick={() => void copy()}\n >\n {state === 'copied' ? (\n <IconCheck className=\"size-3.5\" />\n ) : (\n <IconCopy className=\"size-3.5\" />\n )}\n <span aria-live=\"polite\" className={state === 'error' ? 'text-destructive' : undefined}>\n {state === 'copied' ? copiedLabel : state === 'error' ? 'Copie impossible' : label}\n </span>\n </Button>\n );\n}\n\n// ---------------------------------------------------------------------------\n// Popover\n// ---------------------------------------------------------------------------\n\nexport interface PopoverProps {\n open: boolean;\n onOpenChange: (open: boolean) => void;\n trigger: React.ReactNode;\n children: React.ReactNode;\n align?: 'start' | 'end';\n className?: string;\n}\n\n/** Anchored panel. Controlled — the caller owns `open`. Closes on outside click\n * and Escape, which is what a filter pill needs and a Modal is too heavy for. */\nexport function Popover({\n open,\n onOpenChange,\n trigger,\n children,\n align = 'start',\n className,\n}: PopoverProps) {\n const root = React.useRef<HTMLDivElement>(null);\n\n React.useEffect(() => {\n if (!open) return;\n const onPointerDown = (e: MouseEvent) => {\n if (!root.current?.contains(e.target as Node)) onOpenChange(false);\n };\n const onKeyDown = (e: KeyboardEvent) => {\n if (e.key === 'Escape') onOpenChange(false);\n };\n document.addEventListener('mousedown', onPointerDown);\n document.addEventListener('keydown', onKeyDown);\n return () => {\n document.removeEventListener('mousedown', onPointerDown);\n document.removeEventListener('keydown', onKeyDown);\n };\n }, [open, onOpenChange]);\n\n return (\n <div ref={root} className=\"relative inline-block\">\n <button type=\"button\" aria-expanded={open} onClick={() => onOpenChange(!open)}>\n {trigger}\n </button>\n {open && (\n <div\n className={cn(\n 'absolute z-40 mt-1 min-w-48 rounded-md border bg-card p-2 shadow-lg',\n align === 'end' ? 'right-0' : 'left-0',\n className,\n )}\n >\n {children}\n </div>\n )}\n </div>\n );\n}\n\n// ---------------------------------------------------------------------------\n// DropdownMenu\n// ---------------------------------------------------------------------------\n\nexport interface DropdownMenuItem {\n label: React.ReactNode;\n onSelect: () => void;\n disabled?: boolean;\n destructive?: boolean;\n}\n\nexport interface DropdownMenuProps {\n trigger: React.ReactNode;\n items: DropdownMenuItem[];\n align?: 'start' | 'end';\n className?: string;\n}\n\n/** Uncontrolled menu built on Popover. Selecting an item closes it. */\nexport function DropdownMenu({ trigger, items, align = 'end', className }: DropdownMenuProps) {\n const [open, setOpen] = React.useState(false);\n return (\n <Popover\n open={open}\n onOpenChange={setOpen}\n trigger={trigger}\n align={align}\n className={cn('p-1', className)}\n >\n <div role=\"menu\" className=\"flex flex-col\">\n {items.map((item, i) => (\n <button\n key={i}\n type=\"button\"\n role=\"menuitem\"\n disabled={item.disabled}\n className={cn(\n 'cursor-pointer rounded px-2 py-1.5 text-left text-sm hover:bg-accent disabled:pointer-events-none disabled:opacity-50',\n item.destructive && 'text-destructive',\n )}\n onClick={() => {\n setOpen(false);\n item.onSelect();\n }}\n >\n {item.label}\n </button>\n ))}\n </div>\n </Popover>\n );\n}\n"]}
|
package/dist/index.d.cts
CHANGED
|
@@ -1,20 +1,11 @@
|
|
|
1
1
|
import { ClassValue } from 'clsx';
|
|
2
2
|
import * as React from 'react';
|
|
3
|
+
import { AppErrorCode } from '@apotech-os/app-kit';
|
|
3
4
|
import * as class_variance_authority_types from 'class-variance-authority/types';
|
|
4
5
|
import { VariantProps } from 'class-variance-authority';
|
|
5
6
|
|
|
6
7
|
declare function cn(...inputs: ClassValue[]): string;
|
|
7
8
|
|
|
8
|
-
/**
|
|
9
|
-
* Runtime hooks provided by the shell via @apotech-os/ui-sdk.
|
|
10
|
-
*
|
|
11
|
-
* These hooks are implemented by the shell and injected at runtime via the
|
|
12
|
-
* import map. App pages call them without knowing the shell internals.
|
|
13
|
-
*
|
|
14
|
-
* The default implementations throw if called outside of the shell context
|
|
15
|
-
* (which should never happen in production — the shell always provides them
|
|
16
|
-
* via the import map before mounting an app page).
|
|
17
|
-
*/
|
|
18
9
|
interface AppContextValue {
|
|
19
10
|
/** The slug of the installed app owning this page. */
|
|
20
11
|
appSlug: string;
|
|
@@ -79,9 +70,9 @@ interface AppApiClient {
|
|
|
79
70
|
/** Thrown by AppApiClient.invoke. */
|
|
80
71
|
declare class AppInvokeError extends Error {
|
|
81
72
|
readonly status: number;
|
|
82
|
-
readonly code?: string | undefined;
|
|
73
|
+
readonly code?: (AppErrorCode | (string & {})) | undefined;
|
|
83
74
|
readonly invocationId?: string | undefined;
|
|
84
|
-
constructor(status: number, message: string, code?: string | undefined, invocationId?: string | undefined);
|
|
75
|
+
constructor(status: number, message: string, code?: (AppErrorCode | (string & {})) | undefined, invocationId?: string | undefined);
|
|
85
76
|
}
|
|
86
77
|
declare const AppApiProvider: React.Provider<AppApiClient | null>;
|
|
87
78
|
/**
|
package/dist/index.d.ts
CHANGED
|
@@ -1,20 +1,11 @@
|
|
|
1
1
|
import { ClassValue } from 'clsx';
|
|
2
2
|
import * as React from 'react';
|
|
3
|
+
import { AppErrorCode } from '@apotech-os/app-kit';
|
|
3
4
|
import * as class_variance_authority_types from 'class-variance-authority/types';
|
|
4
5
|
import { VariantProps } from 'class-variance-authority';
|
|
5
6
|
|
|
6
7
|
declare function cn(...inputs: ClassValue[]): string;
|
|
7
8
|
|
|
8
|
-
/**
|
|
9
|
-
* Runtime hooks provided by the shell via @apotech-os/ui-sdk.
|
|
10
|
-
*
|
|
11
|
-
* These hooks are implemented by the shell and injected at runtime via the
|
|
12
|
-
* import map. App pages call them without knowing the shell internals.
|
|
13
|
-
*
|
|
14
|
-
* The default implementations throw if called outside of the shell context
|
|
15
|
-
* (which should never happen in production — the shell always provides them
|
|
16
|
-
* via the import map before mounting an app page).
|
|
17
|
-
*/
|
|
18
9
|
interface AppContextValue {
|
|
19
10
|
/** The slug of the installed app owning this page. */
|
|
20
11
|
appSlug: string;
|
|
@@ -79,9 +70,9 @@ interface AppApiClient {
|
|
|
79
70
|
/** Thrown by AppApiClient.invoke. */
|
|
80
71
|
declare class AppInvokeError extends Error {
|
|
81
72
|
readonly status: number;
|
|
82
|
-
readonly code?: string | undefined;
|
|
73
|
+
readonly code?: (AppErrorCode | (string & {})) | undefined;
|
|
83
74
|
readonly invocationId?: string | undefined;
|
|
84
|
-
constructor(status: number, message: string, code?: string | undefined, invocationId?: string | undefined);
|
|
75
|
+
constructor(status: number, message: string, code?: (AppErrorCode | (string & {})) | undefined, invocationId?: string | undefined);
|
|
85
76
|
}
|
|
86
77
|
declare const AppApiProvider: React.Provider<AppApiClient | null>;
|
|
87
78
|
/**
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/cn.ts","../src/hooks.ts","../src/utils.ts","../src/components.tsx"],"names":["Textarea","Checkbox"],"mappings":"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","file":"index.js","sourcesContent":["import { type ClassValue, clsx } from 'clsx';\nimport { twMerge } from 'tailwind-merge';\n\nexport function cn(...inputs: ClassValue[]): string {\n return twMerge(clsx(inputs));\n}\n","/**\n * Runtime hooks provided by the shell via @apotech-os/ui-sdk.\n *\n * These hooks are implemented by the shell and injected at runtime via the\n * import map. App pages call them without knowing the shell internals.\n *\n * The default implementations throw if called outside of the shell context\n * (which should never happen in production — the shell always provides them\n * via the import map before mounting an app page).\n */\n\nimport { useContext, createContext, useCallback, useEffect, useRef, useState } from 'react';\n\n// ---------------------------------------------------------------------------\n// AppContext\n// ---------------------------------------------------------------------------\n\nexport interface AppContextValue {\n /** The slug of the installed app owning this page. */\n appSlug: string;\n /** The page path within the app (e.g. 'attribution'). */\n pagePath: string;\n /** The active space id, when applicable. */\n spaceId?: string;\n /**\n * The current user's grant role on this app context, when the shell knows it.\n * Settings pages use it to render read-only fields below ADMIN instead of\n * letting the user discover the 403 at save time.\n */\n role?: 'VIEWER' | 'EDITOR' | 'ADMIN';\n}\n\nconst AppContextInternalCtx = createContext<AppContextValue | null>(null);\n\nexport const AppContextProvider = AppContextInternalCtx.Provider;\n\n/** Returns context info for the current app page (appSlug, pagePath, spaceId). */\nexport function useAppContext(): AppContextValue {\n const ctx = useContext(AppContextInternalCtx);\n if (!ctx) throw new Error('useAppContext must be used inside an app page mounted by the shell');\n return ctx;\n}\n\n// ---------------------------------------------------------------------------\n// AppApi\n// ---------------------------------------------------------------------------\n\nexport interface AppApiClient {\n /**\n * Perform a GET request to a platform-data endpoint.\n * The session cookie is forwarded automatically (same-origin, withCredentials).\n */\n get<T>(path: string, params?: Record<string, string>): Promise<T>;\n /**\n * Perform a POST request to a platform-data endpoint.\n */\n post<T>(path: string, body?: unknown): Promise<T>;\n /**\n * Perform a PUT request to a platform-data endpoint (e.g. write app settings).\n */\n put<T>(path: string, body?: unknown): Promise<T>;\n /**\n * Perform a PATCH request to a platform-data endpoint (e.g. update a record).\n */\n patch<T>(path: string, body?: unknown): Promise<T>;\n /**\n * Perform a DELETE request to a platform-data endpoint (e.g. delete a record).\n */\n delete<T>(path: string): Promise<T>;\n /**\n * Run one of this app's `uiInvoke` functions and get its return value back.\n *\n * This is the ONLY way a page can reach an integration: the action endpoint\n * requires an app token and refuses a browser session. The platform mints the\n * token server-side and runs the handler in-process.\n *\n * The function must be declared `trigger: { type: 'uiInvoke' }` in the\n * manifest, and the caller must hold its `minRole` (default EDITOR).\n *\n * Pass `idempotencyKey` for anything that must not run twice on a double\n * click — a concurrent duplicate is rejected with 409 INVOCATION_IN_FLIGHT.\n *\n * Throws AppInvokeError. `code === 'FUNCTION_REJECTED'` carries an app-authored\n * message that is safe to show the user; every other failure is generic on\n * purpose (raw provider errors can leak tokens or PII).\n */\n invoke<TResult, TInput = Record<string, unknown>>(\n functionName: string,\n input?: TInput,\n opts?: { idempotencyKey?: string; signal?: AbortSignal },\n ): Promise<TResult>;\n}\n\n/** Thrown by AppApiClient.invoke. */\nexport class AppInvokeError extends Error {\n constructor(\n readonly status: number,\n message: string,\n readonly code?: string,\n readonly invocationId?: string,\n ) {\n super(message);\n this.name = 'AppInvokeError';\n }\n}\n\nconst AppApiCtx = createContext<AppApiClient | null>(null);\n\nexport const AppApiProvider = AppApiCtx.Provider;\n\n/**\n * Returns an API client scoped to the current user session.\n * Requests go to /api/data/* with the session cookie (RBAC applies server-side).\n */\nexport function useAppApi(): AppApiClient {\n const client = useContext(AppApiCtx);\n if (!client) throw new Error('useAppApi must be used inside an app page mounted by the shell');\n return client;\n}\n\n// ---------------------------------------------------------------------------\n// AppSettings\n// ---------------------------------------------------------------------------\n\n/**\n * Reads and writes this app's settings (GET/PUT /data/apps/:appSlug/settings).\n *\n * The app slug comes from the surrounding AppContext, so a settings page only\n * has to describe its form. Values are the ones the server merged with the\n * `settings.fields` defaults declared in the manifest.\n *\n * Reading requires VIEWER, writing requires ADMIN. `save` never throws: it\n * reports through `saveError`, which carries the raw failure (422\n * SETTINGS_VALIDATION_FAILED with its per-key errors, or 403) so the page can\n * map it back onto its fields. A failed save leaves `settings` untouched.\n */\nexport function useAppSettings<T = Record<string, unknown>>(): {\n settings: T | undefined;\n isLoading: boolean;\n error: unknown;\n save: (patch: Partial<T>) => Promise<void>;\n isSaving: boolean;\n saveError: unknown;\n} {\n const { appSlug } = useAppContext();\n const api = useAppApi();\n const path = `/data/apps/${appSlug}/settings`;\n\n const [settings, setSettings] = useState<T | undefined>(undefined);\n const [isLoading, setIsLoading] = useState(true);\n const [error, setError] = useState<unknown>(undefined);\n const [isSaving, setIsSaving] = useState(false);\n const [saveError, setSaveError] = useState<unknown>(undefined);\n\n // The shell rebuilds the client on every render, so it cannot be an effect\n // dependency without refetching in a loop.\n const clientRef = useRef(api);\n clientRef.current = api;\n // Bumped by every request and by unmount: a superseded or late response is\n // dropped instead of overwriting fresher state.\n const requestIdRef = useRef(0);\n const isMountedRef = useRef(true);\n\n /**\n * `silent` skips the isLoading flip for the refetch that follows a save: a page\n * written as `if (isLoading) return <Spinner/>` would otherwise unmount its own\n * form mid-save, losing focus and any uncommitted input. isSaving already covers\n * that window.\n */\n const load = useCallback(\n async ({ silent }: { silent?: boolean } = {}) => {\n const requestId = ++requestIdRef.current;\n if (!silent) setIsLoading(true);\n try {\n const loaded = await clientRef.current.get<T>(path);\n if (requestId !== requestIdRef.current) return;\n setSettings(loaded);\n setError(undefined);\n } catch (err) {\n if (requestId !== requestIdRef.current) return;\n setError(err);\n } finally {\n // Clearing is NOT conditional on `silent`: a save that races the very first\n // GET supersedes it, so the initial load can no longer clear the flag it\n // set — only the request that actually settles last can.\n if (requestId === requestIdRef.current) setIsLoading(false);\n }\n },\n [path],\n );\n\n useEffect(() => {\n isMountedRef.current = true;\n void load();\n return () => {\n isMountedRef.current = false;\n requestIdRef.current += 1;\n };\n }, [load]);\n\n const save = useCallback(\n async (patch: Partial<T>) => {\n setIsSaving(true);\n setSaveError(undefined);\n try {\n await clientRef.current.put<unknown>(path, patch);\n await load({ silent: true });\n } catch (err) {\n if (isMountedRef.current) setSaveError(err);\n } finally {\n if (isMountedRef.current) setIsSaving(false);\n }\n },\n [path, load],\n );\n\n return { settings, isLoading, error, save, isSaving, saveError };\n}\n","/**\n * Browser helpers for app pages.\n *\n * App bundles get react, react-dom and this SDK from the shell's import map and\n * bundle everything else themselves — so without these here, every app would\n * reimplement clipboard handling and CSV escaping, and get the edge cases wrong\n * in its own way.\n */\n\n/**\n * Copy text to the clipboard.\n *\n * Returns `false` instead of throwing when the clipboard is unavailable (non\n * secure context, permission refused) so the caller can render inline feedback.\n * No `document.execCommand('copy')` fallback: it is deprecated, and the shell\n * only ever runs on https or localhost, both secure contexts.\n */\nexport async function copyToClipboard(text: string): Promise<boolean> {\n if (!navigator?.clipboard || !window.isSecureContext) return false;\n try {\n await navigator.clipboard.writeText(text);\n return true;\n } catch {\n return false;\n }\n}\n\n/** Trigger a browser download of a Blob via a throwaway object URL + `<a>` click. */\nexport function downloadBlob(blob: Blob, filename: string): void {\n const url = URL.createObjectURL(blob);\n const a = document.createElement('a');\n a.href = url;\n a.download = filename;\n document.body.appendChild(a);\n a.click();\n a.remove();\n URL.revokeObjectURL(url);\n}\n\n/** Escape one CSV field per RFC 4180: quote it, and double any embedded quote,\n * whenever it contains a comma, a quote, or a line break. */\nfunction escapeCsvField(value: string): string {\n return /[\",\\r\\n]/.test(value) ? `\"${value.replace(/\"/g, '\"\"')}\"` : value;\n}\n\n/** Serialize rows (header included) into an RFC 4180 CSV string. */\nexport function toCsv(rows: string[][]): string {\n return rows.map((row) => row.map(escapeCsvField).join(',')).join('\\r\\n');\n}\n\n/** UTF-8 byte order mark. */\nconst BOM = '\\uFEFF';\n\n/**\n * Serialize + download in one call.\n *\n * The BOM is the whole reason this helper exists: without it Excel on Windows\n * reads the file as latin-1 and mangles every accented character.\n */\nexport function downloadCsv(rows: string[][], filename: string): void {\n const blob = new Blob([`${BOM}${toCsv(rows)}`], { type: 'text/csv;charset=utf-8' });\n downloadBlob(blob, filename);\n}\n","/**\n * Design system components exported by @apotech-os/ui-sdk.\n *\n * These are minimal self-contained copies of the shell's component library.\n * They use the same Tailwind utility classes as the shell — Tailwind classes\n * are plain strings and work without any build step when the shell's stylesheet\n * is loaded (which it is, since these pages run inside the shell).\n *\n * Strategy note:\n * - Not imported from apps/web (would create a circular dep pkg → app).\n * - Copied/adapted here to keep the SDK self-contained and publishable.\n * - The exhaustive component inventory is tracked in #75.\n */\n\nimport { type VariantProps, cva } from 'class-variance-authority';\nimport * as React from 'react';\nimport { cn } from './cn';\nimport { copyToClipboard } from './utils';\n\n// ---------------------------------------------------------------------------\n// Button\n// ---------------------------------------------------------------------------\n\nconst buttonVariants = cva(\n 'inline-flex cursor-pointer items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-50',\n {\n variants: {\n variant: {\n default: 'bg-primary text-primary-foreground hover:bg-primary/90',\n secondary: 'bg-secondary text-secondary-foreground hover:bg-secondary/80',\n outline: 'border border-input bg-background hover:bg-accent hover:text-accent-foreground',\n ghost: 'hover:bg-accent hover:text-accent-foreground',\n destructive: 'bg-destructive text-white hover:bg-destructive/90',\n },\n size: {\n default: 'h-9 px-4 py-2',\n sm: 'h-8 rounded-md px-3 text-xs',\n lg: 'h-10 rounded-md px-6',\n icon: 'h-9 w-9',\n },\n },\n defaultVariants: { variant: 'default', size: 'default' },\n },\n);\n\nexport interface ButtonProps\n extends React.ButtonHTMLAttributes<HTMLButtonElement>, VariantProps<typeof buttonVariants> {}\n\nexport const Button = React.forwardRef<HTMLButtonElement, ButtonProps>(\n ({ className, variant, size, ...props }, ref) => (\n <button ref={ref} className={cn(buttonVariants({ variant, size, className }))} {...props} />\n ),\n);\nButton.displayName = 'Button';\n\n// ---------------------------------------------------------------------------\n// Badge\n// ---------------------------------------------------------------------------\n\nconst badgeVariants = cva(\n 'inline-flex items-center gap-1.5 rounded-full border px-2 py-0.5 text-xs font-medium whitespace-nowrap',\n {\n variants: {\n variant: {\n neutral: 'border-border bg-muted text-muted-foreground',\n brand: 'border-primary/20 bg-primary/10 text-primary',\n success: 'border-status-success/25 bg-status-success/10 text-status-success',\n warning: 'border-status-pending/30 bg-status-pending/10 text-status-pending',\n danger: 'border-status-blocked/25 bg-status-blocked/10 text-status-blocked',\n info: 'border-status-info/25 bg-status-info/10 text-status-info',\n outline: 'border-border bg-transparent text-muted-foreground',\n },\n },\n defaultVariants: { variant: 'neutral' },\n },\n);\n\nexport interface BadgeProps\n extends React.HTMLAttributes<HTMLSpanElement>, VariantProps<typeof badgeVariants> {\n dot?: boolean;\n}\n\nexport function Badge({ className, variant, dot, children, ...props }: BadgeProps) {\n return (\n <span className={cn(badgeVariants({ variant }), className)} {...props}>\n {dot && <span className=\"size-1.5 rounded-full bg-current\" />}\n {children}\n </span>\n );\n}\n\n// ---------------------------------------------------------------------------\n// Card\n// ---------------------------------------------------------------------------\n\nexport function Card({ className, ...props }: React.HTMLAttributes<HTMLDivElement>) {\n return (\n <div\n className={cn('rounded-xl border bg-card text-card-foreground shadow-sm', className)}\n {...props}\n />\n );\n}\n\nexport function CardHeader({ className, ...props }: React.HTMLAttributes<HTMLDivElement>) {\n return <div className={cn('flex flex-col space-y-1.5 p-6', className)} {...props} />;\n}\n\nexport function CardTitle({ className, ...props }: React.HTMLAttributes<HTMLHeadingElement>) {\n return (\n <h3 className={cn('text-lg font-semibold leading-none tracking-tight', className)} {...props} />\n );\n}\n\nexport function CardContent({ className, ...props }: React.HTMLAttributes<HTMLDivElement>) {\n return <div className={cn('p-6 pt-0', className)} {...props} />;\n}\n\n// ---------------------------------------------------------------------------\n// Input\n// ---------------------------------------------------------------------------\n\nexport const Input = React.forwardRef<\n HTMLInputElement,\n React.InputHTMLAttributes<HTMLInputElement>\n>(({ className, type, ...props }, ref) => (\n <input\n type={type}\n className={cn(\n 'flex h-9 w-full rounded-md border border-input bg-transparent px-3 py-1 text-sm shadow-sm transition-colors file:border-0 file:bg-transparent file:text-sm file:font-medium placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:cursor-not-allowed disabled:opacity-50',\n className,\n )}\n ref={ref}\n {...props}\n />\n));\nInput.displayName = 'Input';\n\n// ---------------------------------------------------------------------------\n// Table\n// ---------------------------------------------------------------------------\n\nexport function Table({ className, ...props }: React.HTMLAttributes<HTMLTableElement>) {\n return <table className={cn('w-full text-sm', className)} {...props} />;\n}\n\nexport function TableHeader({\n className,\n ...props\n}: React.HTMLAttributes<HTMLTableSectionElement>) {\n return <thead className={cn('[&_tr]:border-b', className)} {...props} />;\n}\n\nexport function TableBody({ className, ...props }: React.HTMLAttributes<HTMLTableSectionElement>) {\n return <tbody className={cn('[&_tr:last-child]:border-0', className)} {...props} />;\n}\n\nexport function TableRow({ className, ...props }: React.HTMLAttributes<HTMLTableRowElement>) {\n return (\n <tr\n className={cn(\n 'border-b transition-colors hover:bg-muted/50 data-[state=selected]:bg-muted',\n className,\n )}\n {...props}\n />\n );\n}\n\nexport function TableHead({ className, ...props }: React.ThHTMLAttributes<HTMLTableCellElement>) {\n return (\n <th\n className={cn(\n 'h-10 px-4 text-left align-middle text-xs font-medium text-muted-foreground',\n className,\n )}\n {...props}\n />\n );\n}\n\nexport function TableCell({ className, ...props }: React.TdHTMLAttributes<HTMLTableCellElement>) {\n return <td className={cn('p-4 align-middle', className)} {...props} />;\n}\n\n// ---------------------------------------------------------------------------\n// Select\n// ---------------------------------------------------------------------------\n\nexport interface SelectProps extends React.SelectHTMLAttributes<HTMLSelectElement> {}\n\nexport const Select = React.forwardRef<HTMLSelectElement, SelectProps>(\n ({ className, children, ...props }, ref) => (\n <select\n ref={ref}\n className={cn(\n 'flex h-9 w-full rounded-md border border-input bg-transparent px-3 py-1 text-sm shadow-sm transition-colors focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:cursor-not-allowed disabled:opacity-50',\n className,\n )}\n {...props}\n >\n {children}\n </select>\n ),\n);\nSelect.displayName = 'Select';\n\n// ---------------------------------------------------------------------------\n// Tabs\n// ---------------------------------------------------------------------------\n\ninterface TabsContextValue {\n value: string;\n setValue: (v: string) => void;\n}\n\nconst TabsContext = React.createContext<TabsContextValue | null>(null);\n\nfunction useTabsContext(): TabsContextValue {\n const ctx = React.useContext(TabsContext);\n if (!ctx) throw new Error('Tabs sub-component must be used within <Tabs>');\n return ctx;\n}\n\nexport interface TabsProps {\n defaultValue?: string;\n value?: string;\n onValueChange?: (v: string) => void;\n className?: string;\n children: React.ReactNode;\n}\n\nexport function Tabs({ defaultValue, value, onValueChange, className, children }: TabsProps) {\n const [internal, setInternal] = React.useState(defaultValue ?? '');\n const current = value ?? internal;\n const setValue = (v: string) => {\n setInternal(v);\n onValueChange?.(v);\n };\n return (\n <TabsContext.Provider value={{ value: current, setValue }}>\n <div className={className}>{children}</div>\n </TabsContext.Provider>\n );\n}\n\nexport function TabsList({\n className,\n children,\n}: {\n className?: string;\n children: React.ReactNode;\n}) {\n return (\n <div className={cn('inline-flex items-center gap-1 rounded-lg bg-muted p-1', className)}>\n {children}\n </div>\n );\n}\n\nexport function TabsTrigger({\n value,\n className,\n children,\n}: {\n value: string;\n className?: string;\n children: React.ReactNode;\n}) {\n const { value: current, setValue } = useTabsContext();\n const active = current === value;\n return (\n <button\n type=\"button\"\n onClick={() => setValue(value)}\n className={cn(\n 'rounded-md px-3 py-1.5 text-sm font-medium transition-colors',\n active\n ? 'bg-card text-foreground shadow-sm'\n : 'text-muted-foreground hover:text-foreground',\n className,\n )}\n >\n {children}\n </button>\n );\n}\n\nexport function TabsContent({\n value,\n className,\n children,\n}: {\n value: string;\n className?: string;\n children: React.ReactNode;\n}) {\n const { value: current } = useTabsContext();\n if (current !== value) return null;\n return <div className={className}>{children}</div>;\n}\n\n// ---------------------------------------------------------------------------\n// Modal (controlled, no Radix)\n// ---------------------------------------------------------------------------\n\nexport interface ModalProps {\n open: boolean;\n onClose: () => void;\n title?: React.ReactNode;\n children: React.ReactNode;\n className?: string;\n}\n\nexport function Modal({ open, onClose, title, children, className }: ModalProps) {\n if (!open) return null;\n return (\n <div className=\"fixed inset-0 z-50 flex items-center justify-center p-4\">\n <button\n type=\"button\"\n aria-label=\"Close\"\n className=\"absolute inset-0 cursor-default bg-foreground/40\"\n onClick={onClose}\n />\n <div\n role=\"dialog\"\n aria-modal\n className={cn(\n 'relative z-10 w-full max-w-md rounded-xl border bg-card p-5 shadow-lg',\n className,\n )}\n >\n {title && <h2 className=\"mb-3 text-base font-semibold\">{title}</h2>}\n {children}\n </div>\n </div>\n );\n}\n\n// ---------------------------------------------------------------------------\n// Spinner\n// ---------------------------------------------------------------------------\n\nexport interface SpinnerProps {\n className?: string;\n size?: 'sm' | 'md' | 'lg';\n}\n\nconst spinnerSizes = { sm: 'size-4', md: 'size-6', lg: 'size-8' };\n\nexport function Spinner({ className, size = 'md' }: SpinnerProps) {\n return (\n <svg\n className={cn('animate-spin text-muted-foreground', spinnerSizes[size], className)}\n xmlns=\"http://www.w3.org/2000/svg\"\n fill=\"none\"\n viewBox=\"0 0 24 24\"\n aria-label=\"Loading\"\n role=\"status\"\n >\n <circle className=\"opacity-25\" cx=\"12\" cy=\"12\" r=\"10\" stroke=\"currentColor\" strokeWidth=\"4\" />\n <path\n className=\"opacity-75\"\n fill=\"currentColor\"\n d=\"M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4z\"\n />\n </svg>\n );\n}\n\n// ---------------------------------------------------------------------------\n// Link\n// ---------------------------------------------------------------------------\n\nexport interface LinkProps extends React.AnchorHTMLAttributes<HTMLAnchorElement> {\n variant?: 'default' | 'muted';\n}\n\nexport const Link = React.forwardRef<HTMLAnchorElement, LinkProps>(\n ({ className, variant = 'default', ...props }, ref) => (\n <a\n ref={ref}\n className={cn(\n 'underline-offset-4 hover:underline focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring',\n variant === 'default' ? 'text-primary' : 'text-muted-foreground',\n className,\n )}\n {...props}\n />\n ),\n);\nLink.displayName = 'Link';\n\n// ---------------------------------------------------------------------------\n// Switch\n// ---------------------------------------------------------------------------\n\nexport interface SwitchProps {\n checked?: boolean;\n onCheckedChange?: (checked: boolean) => void;\n disabled?: boolean;\n className?: string;\n 'aria-label'?: string;\n}\n\nexport function Switch({\n checked = false,\n onCheckedChange,\n disabled,\n className,\n ...props\n}: SwitchProps) {\n return (\n <button\n type=\"button\"\n role=\"switch\"\n aria-checked={checked}\n disabled={disabled}\n onClick={() => onCheckedChange?.(!checked)}\n className={cn(\n 'relative inline-flex h-5 w-9 shrink-0 cursor-pointer items-center rounded-full transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring disabled:cursor-not-allowed disabled:opacity-50',\n checked ? 'bg-primary' : 'bg-input',\n className,\n )}\n {...props}\n >\n <span\n className={cn(\n 'inline-block size-4 transform rounded-full bg-white shadow transition-transform',\n checked ? 'translate-x-4' : 'translate-x-0.5',\n )}\n />\n </button>\n );\n}\n\n// ---------------------------------------------------------------------------\n// DateRangePicker\n// ---------------------------------------------------------------------------\n\nexport interface DateRange {\n from: string;\n to: string;\n}\n\nexport interface DateRangePickerProps {\n value: DateRange;\n onChange: (range: DateRange) => void;\n className?: string;\n disabled?: boolean;\n}\n\n/** Minimal controlled date-range picker using two native date inputs. */\nexport function DateRangePicker({ value, onChange, className, disabled }: DateRangePickerProps) {\n return (\n <div className={cn('flex items-center gap-2', className)}>\n <input\n type=\"date\"\n disabled={disabled}\n value={value.from}\n max={value.to || undefined}\n onChange={(e) => onChange({ ...value, from: e.target.value })}\n className=\"flex h-9 rounded-md border border-input bg-transparent px-3 py-1 text-sm shadow-sm transition-colors focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:cursor-not-allowed disabled:opacity-50\"\n />\n <span className=\"text-muted-foreground text-sm\">→</span>\n <input\n type=\"date\"\n disabled={disabled}\n value={value.to}\n min={value.from || undefined}\n onChange={(e) => onChange({ ...value, to: e.target.value })}\n className=\"flex h-9 rounded-md border border-input bg-transparent px-3 py-1 text-sm shadow-sm transition-colors focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:cursor-not-allowed disabled:opacity-50\"\n />\n </div>\n );\n}\n\n// ---------------------------------------------------------------------------\n// Icons\n//\n// Inline SVGs rather than a lucide-react dependency: the SDK is loaded through\n// the shell's import map as a single vendor chunk, so a dependency here inflates\n// every app page. Same precedent as Spinner above.\n// ---------------------------------------------------------------------------\n\nfunction IconX({ className }: { className?: string }) {\n return (\n <svg\n className={className}\n xmlns=\"http://www.w3.org/2000/svg\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"2\"\n strokeLinecap=\"round\"\n aria-hidden=\"true\"\n >\n <path d=\"M18 6 6 18M6 6l12 12\" />\n </svg>\n );\n}\n\nfunction IconCopy({ className }: { className?: string }) {\n return (\n <svg\n className={className}\n xmlns=\"http://www.w3.org/2000/svg\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"2\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n aria-hidden=\"true\"\n >\n <rect width=\"14\" height=\"14\" x=\"8\" y=\"8\" rx=\"2\" ry=\"2\" />\n <path d=\"M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2\" />\n </svg>\n );\n}\n\nfunction IconCheck({ className }: { className?: string }) {\n return (\n <svg\n className={className}\n xmlns=\"http://www.w3.org/2000/svg\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"2\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n aria-hidden=\"true\"\n >\n <path d=\"M20 6 9 17l-5-5\" />\n </svg>\n );\n}\n\n// ---------------------------------------------------------------------------\n// Textarea\n// ---------------------------------------------------------------------------\n\nexport type TextareaProps = React.TextareaHTMLAttributes<HTMLTextAreaElement>;\n\nexport const Textarea = React.forwardRef<HTMLTextAreaElement, TextareaProps>(\n function Textarea({ className, ...props }, ref) {\n return (\n <textarea\n ref={ref}\n className={cn(\n 'flex min-h-20 w-full rounded-md border border-input bg-transparent px-3 py-2 text-sm shadow-sm transition-colors placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:cursor-not-allowed disabled:opacity-50',\n className,\n )}\n {...props}\n />\n );\n },\n);\n\n// ---------------------------------------------------------------------------\n// Checkbox\n// ---------------------------------------------------------------------------\n\nexport interface CheckboxProps\n extends Omit<React.InputHTMLAttributes<HTMLInputElement>, 'type' | 'onChange'> {\n checked?: boolean;\n /** Preferred over onChange — receives the boolean directly. */\n onCheckedChange?: (checked: boolean) => void;\n label?: React.ReactNode;\n}\n\nexport const Checkbox = React.forwardRef<HTMLInputElement, CheckboxProps>(\n function Checkbox({ className, label, onCheckedChange, ...props }, ref) {\n const input = (\n <input\n ref={ref}\n type=\"checkbox\"\n className={cn(\n 'size-4 shrink-0 cursor-pointer rounded border-input accent-primary disabled:cursor-not-allowed disabled:opacity-50',\n className,\n )}\n onChange={(e) => onCheckedChange?.(e.target.checked)}\n {...props}\n />\n );\n if (!label) return input;\n return (\n <label className=\"inline-flex cursor-pointer items-center gap-2 text-sm\">\n {input}\n <span>{label}</span>\n </label>\n );\n },\n);\n\n// ---------------------------------------------------------------------------\n// SidePanel\n// ---------------------------------------------------------------------------\n\nexport interface SidePanelProps {\n open: boolean;\n onClose: () => void;\n title?: React.ReactNode;\n description?: React.ReactNode;\n children: React.ReactNode;\n className?: string;\n}\n\n/**\n * Blocking slide-over — reach for it when a task has more fields than a `Modal`\n * can show without an inner scrollbar. Full height, so the body scrolls once and\n * a footer can stay pinned; `Modal` centres a box and does no height management.\n *\n * Children are laid out in a flex column filling the panel: put the scrollable\n * region in a `min-h-0 flex-1 overflow-y-auto` child and the footer after it.\n *\n * NOTE: no focus management. Autofocus the primary action yourself.\n */\nexport function SidePanel({\n open,\n onClose,\n title,\n description,\n children,\n className,\n}: SidePanelProps) {\n // Escape closes. A panel that covers the viewport makes a missing keyboard\n // exit far more noticeable than it is on a centred Modal.\n React.useEffect(() => {\n if (!open) return;\n const onKeyDown = (e: KeyboardEvent) => {\n if (e.key === 'Escape') onClose();\n };\n window.addEventListener('keydown', onKeyDown);\n return () => window.removeEventListener('keydown', onKeyDown);\n }, [open, onClose]);\n\n if (!open) return null;\n return (\n <div className=\"fixed inset-0 z-50\">\n <button\n type=\"button\"\n aria-label=\"Fermer\"\n className=\"absolute inset-0 cursor-default bg-foreground/40\"\n onClick={onClose}\n />\n <aside\n role=\"dialog\"\n aria-modal\n className={cn(\n 'absolute inset-y-0 right-0 flex w-full max-w-lg flex-col border-l bg-card shadow-xl',\n className,\n )}\n >\n <header className=\"flex shrink-0 items-start gap-3 border-b px-5 py-4\">\n <div className=\"min-w-0 flex-1\">\n {title && <h2 className=\"text-base font-semibold\">{title}</h2>}\n {description && <p className=\"mt-0.5 text-xs text-muted-foreground\">{description}</p>}\n </div>\n <button\n type=\"button\"\n aria-label=\"Fermer\"\n className=\"-mr-1 shrink-0 rounded-md p-1 text-muted-foreground hover:bg-accent hover:text-foreground\"\n onClick={onClose}\n >\n <IconX className=\"size-4\" />\n </button>\n </header>\n <div className=\"flex min-h-0 flex-1 flex-col px-5 py-4\">{children}</div>\n </aside>\n </div>\n );\n}\n\n// ---------------------------------------------------------------------------\n// CopyButton\n// ---------------------------------------------------------------------------\n\nexport interface CopyButtonProps {\n value: string;\n label?: string;\n copiedLabel?: string;\n variant?: ButtonProps['variant'];\n size?: ButtonProps['size'];\n className?: string;\n}\n\n/** How long the confirmation stays up before reverting. */\nconst COPY_FEEDBACK_MS = 2000;\n\n/**\n * Copy-to-clipboard button with inline feedback. On failure it says so rather\n * than silently doing nothing — keep the copyable text selectable so manual\n * copy stays the fallback.\n */\nexport function CopyButton({\n value,\n label = 'Copier',\n copiedLabel = 'Copié',\n variant = 'outline',\n size = 'sm',\n className,\n}: CopyButtonProps) {\n const [state, setState] = React.useState<'idle' | 'copied' | 'error'>('idle');\n const timeout = React.useRef<ReturnType<typeof setTimeout> | undefined>(undefined);\n\n // Held in a ref and cleared on unmount: the panel can close mid-feedback.\n React.useEffect(() => () => clearTimeout(timeout.current), []);\n\n async function copy() {\n const ok = await copyToClipboard(value);\n setState(ok ? 'copied' : 'error');\n clearTimeout(timeout.current);\n timeout.current = setTimeout(() => setState('idle'), COPY_FEEDBACK_MS);\n }\n\n return (\n <Button\n type=\"button\"\n variant={variant}\n size={size}\n className={className}\n onClick={() => void copy()}\n >\n {state === 'copied' ? (\n <IconCheck className=\"size-3.5\" />\n ) : (\n <IconCopy className=\"size-3.5\" />\n )}\n <span aria-live=\"polite\" className={state === 'error' ? 'text-destructive' : undefined}>\n {state === 'copied' ? copiedLabel : state === 'error' ? 'Copie impossible' : label}\n </span>\n </Button>\n );\n}\n\n// ---------------------------------------------------------------------------\n// Popover\n// ---------------------------------------------------------------------------\n\nexport interface PopoverProps {\n open: boolean;\n onOpenChange: (open: boolean) => void;\n trigger: React.ReactNode;\n children: React.ReactNode;\n align?: 'start' | 'end';\n className?: string;\n}\n\n/** Anchored panel. Controlled — the caller owns `open`. Closes on outside click\n * and Escape, which is what a filter pill needs and a Modal is too heavy for. */\nexport function Popover({\n open,\n onOpenChange,\n trigger,\n children,\n align = 'start',\n className,\n}: PopoverProps) {\n const root = React.useRef<HTMLDivElement>(null);\n\n React.useEffect(() => {\n if (!open) return;\n const onPointerDown = (e: MouseEvent) => {\n if (!root.current?.contains(e.target as Node)) onOpenChange(false);\n };\n const onKeyDown = (e: KeyboardEvent) => {\n if (e.key === 'Escape') onOpenChange(false);\n };\n document.addEventListener('mousedown', onPointerDown);\n document.addEventListener('keydown', onKeyDown);\n return () => {\n document.removeEventListener('mousedown', onPointerDown);\n document.removeEventListener('keydown', onKeyDown);\n };\n }, [open, onOpenChange]);\n\n return (\n <div ref={root} className=\"relative inline-block\">\n <button type=\"button\" aria-expanded={open} onClick={() => onOpenChange(!open)}>\n {trigger}\n </button>\n {open && (\n <div\n className={cn(\n 'absolute z-40 mt-1 min-w-48 rounded-md border bg-card p-2 shadow-lg',\n align === 'end' ? 'right-0' : 'left-0',\n className,\n )}\n >\n {children}\n </div>\n )}\n </div>\n );\n}\n\n// ---------------------------------------------------------------------------\n// DropdownMenu\n// ---------------------------------------------------------------------------\n\nexport interface DropdownMenuItem {\n label: React.ReactNode;\n onSelect: () => void;\n disabled?: boolean;\n destructive?: boolean;\n}\n\nexport interface DropdownMenuProps {\n trigger: React.ReactNode;\n items: DropdownMenuItem[];\n align?: 'start' | 'end';\n className?: string;\n}\n\n/** Uncontrolled menu built on Popover. Selecting an item closes it. */\nexport function DropdownMenu({ trigger, items, align = 'end', className }: DropdownMenuProps) {\n const [open, setOpen] = React.useState(false);\n return (\n <Popover\n open={open}\n onOpenChange={setOpen}\n trigger={trigger}\n align={align}\n className={cn('p-1', className)}\n >\n <div role=\"menu\" className=\"flex flex-col\">\n {items.map((item, i) => (\n <button\n key={i}\n type=\"button\"\n role=\"menuitem\"\n disabled={item.disabled}\n className={cn(\n 'cursor-pointer rounded px-2 py-1.5 text-left text-sm hover:bg-accent disabled:pointer-events-none disabled:opacity-50',\n item.destructive && 'text-destructive',\n )}\n onClick={() => {\n setOpen(false);\n item.onSelect();\n }}\n >\n {item.label}\n </button>\n ))}\n </div>\n </Popover>\n );\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/cn.ts","../src/hooks.ts","../src/utils.ts","../src/components.tsx"],"names":["Textarea","Checkbox"],"mappings":"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","file":"index.js","sourcesContent":["import { type ClassValue, clsx } from 'clsx';\nimport { twMerge } from 'tailwind-merge';\n\nexport function cn(...inputs: ClassValue[]): string {\n return twMerge(clsx(inputs));\n}\n","/**\n * Runtime hooks provided by the shell via @apotech-os/ui-sdk.\n *\n * These hooks are implemented by the shell and injected at runtime via the\n * import map. App pages call them without knowing the shell internals.\n *\n * The default implementations throw if called outside of the shell context\n * (which should never happen in production — the shell always provides them\n * via the import map before mounting an app page).\n */\n\nimport { useContext, createContext, useCallback, useEffect, useRef, useState } from 'react';\n// `import type` only: ui-sdk has no runtime dependency on app-kit, so this must\n// not appear in the built dist/index.js (verified — see error-codes.ts).\nimport type { AppErrorCode } from '@apotech-os/app-kit';\n\n// ---------------------------------------------------------------------------\n// AppContext\n// ---------------------------------------------------------------------------\n\nexport interface AppContextValue {\n /** The slug of the installed app owning this page. */\n appSlug: string;\n /** The page path within the app (e.g. 'attribution'). */\n pagePath: string;\n /** The active space id, when applicable. */\n spaceId?: string;\n /**\n * The current user's grant role on this app context, when the shell knows it.\n * Settings pages use it to render read-only fields below ADMIN instead of\n * letting the user discover the 403 at save time.\n */\n role?: 'VIEWER' | 'EDITOR' | 'ADMIN';\n}\n\nconst AppContextInternalCtx = createContext<AppContextValue | null>(null);\n\nexport const AppContextProvider = AppContextInternalCtx.Provider;\n\n/** Returns context info for the current app page (appSlug, pagePath, spaceId). */\nexport function useAppContext(): AppContextValue {\n const ctx = useContext(AppContextInternalCtx);\n if (!ctx) throw new Error('useAppContext must be used inside an app page mounted by the shell');\n return ctx;\n}\n\n// ---------------------------------------------------------------------------\n// AppApi\n// ---------------------------------------------------------------------------\n\nexport interface AppApiClient {\n /**\n * Perform a GET request to a platform-data endpoint.\n * The session cookie is forwarded automatically (same-origin, withCredentials).\n */\n get<T>(path: string, params?: Record<string, string>): Promise<T>;\n /**\n * Perform a POST request to a platform-data endpoint.\n */\n post<T>(path: string, body?: unknown): Promise<T>;\n /**\n * Perform a PUT request to a platform-data endpoint (e.g. write app settings).\n */\n put<T>(path: string, body?: unknown): Promise<T>;\n /**\n * Perform a PATCH request to a platform-data endpoint (e.g. update a record).\n */\n patch<T>(path: string, body?: unknown): Promise<T>;\n /**\n * Perform a DELETE request to a platform-data endpoint (e.g. delete a record).\n */\n delete<T>(path: string): Promise<T>;\n /**\n * Run one of this app's `uiInvoke` functions and get its return value back.\n *\n * This is the ONLY way a page can reach an integration: the action endpoint\n * requires an app token and refuses a browser session. The platform mints the\n * token server-side and runs the handler in-process.\n *\n * The function must be declared `trigger: { type: 'uiInvoke' }` in the\n * manifest, and the caller must hold its `minRole` (default EDITOR).\n *\n * Pass `idempotencyKey` for anything that must not run twice on a double\n * click — a concurrent duplicate is rejected with 409 INVOCATION_IN_FLIGHT.\n *\n * Throws AppInvokeError. `code === 'FUNCTION_REJECTED'` carries an app-authored\n * message that is safe to show the user; every other failure is generic on\n * purpose (raw provider errors can leak tokens or PII).\n */\n invoke<TResult, TInput = Record<string, unknown>>(\n functionName: string,\n input?: TInput,\n opts?: { idempotencyKey?: string; signal?: AbortSignal },\n ): Promise<TResult>;\n}\n\n/** Thrown by AppApiClient.invoke. */\nexport class AppInvokeError extends Error {\n constructor(\n readonly status: number,\n message: string,\n // `AppErrorCode | (string & {})` gives autocomplete on the known codes\n // while keeping any other string assignable — a server that returns an\n // unlisted `code` (or none) must not fail to compile against this type.\n readonly code?: AppErrorCode | (string & {}),\n readonly invocationId?: string,\n ) {\n super(message);\n this.name = 'AppInvokeError';\n }\n}\n\nconst AppApiCtx = createContext<AppApiClient | null>(null);\n\nexport const AppApiProvider = AppApiCtx.Provider;\n\n/**\n * Returns an API client scoped to the current user session.\n * Requests go to /api/data/* with the session cookie (RBAC applies server-side).\n */\nexport function useAppApi(): AppApiClient {\n const client = useContext(AppApiCtx);\n if (!client) throw new Error('useAppApi must be used inside an app page mounted by the shell');\n return client;\n}\n\n// ---------------------------------------------------------------------------\n// AppSettings\n// ---------------------------------------------------------------------------\n\n/**\n * Reads and writes this app's settings (GET/PUT /data/apps/:appSlug/settings).\n *\n * The app slug comes from the surrounding AppContext, so a settings page only\n * has to describe its form. Values are the ones the server merged with the\n * `settings.fields` defaults declared in the manifest.\n *\n * Reading requires VIEWER, writing requires ADMIN. `save` never throws: it\n * reports through `saveError`, which carries the raw failure (422\n * SETTINGS_VALIDATION_FAILED with its per-key errors, or 403) so the page can\n * map it back onto its fields. A failed save leaves `settings` untouched.\n */\nexport function useAppSettings<T = Record<string, unknown>>(): {\n settings: T | undefined;\n isLoading: boolean;\n error: unknown;\n save: (patch: Partial<T>) => Promise<void>;\n isSaving: boolean;\n saveError: unknown;\n} {\n const { appSlug } = useAppContext();\n const api = useAppApi();\n const path = `/data/apps/${appSlug}/settings`;\n\n const [settings, setSettings] = useState<T | undefined>(undefined);\n const [isLoading, setIsLoading] = useState(true);\n const [error, setError] = useState<unknown>(undefined);\n const [isSaving, setIsSaving] = useState(false);\n const [saveError, setSaveError] = useState<unknown>(undefined);\n\n // The shell rebuilds the client on every render, so it cannot be an effect\n // dependency without refetching in a loop.\n const clientRef = useRef(api);\n clientRef.current = api;\n // Bumped by every request and by unmount: a superseded or late response is\n // dropped instead of overwriting fresher state.\n const requestIdRef = useRef(0);\n const isMountedRef = useRef(true);\n\n /**\n * `silent` skips the isLoading flip for the refetch that follows a save: a page\n * written as `if (isLoading) return <Spinner/>` would otherwise unmount its own\n * form mid-save, losing focus and any uncommitted input. isSaving already covers\n * that window.\n */\n const load = useCallback(\n async ({ silent }: { silent?: boolean } = {}) => {\n const requestId = ++requestIdRef.current;\n if (!silent) setIsLoading(true);\n try {\n const loaded = await clientRef.current.get<T>(path);\n if (requestId !== requestIdRef.current) return;\n setSettings(loaded);\n setError(undefined);\n } catch (err) {\n if (requestId !== requestIdRef.current) return;\n setError(err);\n } finally {\n // Clearing is NOT conditional on `silent`: a save that races the very first\n // GET supersedes it, so the initial load can no longer clear the flag it\n // set — only the request that actually settles last can.\n if (requestId === requestIdRef.current) setIsLoading(false);\n }\n },\n [path],\n );\n\n useEffect(() => {\n isMountedRef.current = true;\n void load();\n return () => {\n isMountedRef.current = false;\n requestIdRef.current += 1;\n };\n }, [load]);\n\n const save = useCallback(\n async (patch: Partial<T>) => {\n setIsSaving(true);\n setSaveError(undefined);\n try {\n await clientRef.current.put<unknown>(path, patch);\n await load({ silent: true });\n } catch (err) {\n if (isMountedRef.current) setSaveError(err);\n } finally {\n if (isMountedRef.current) setIsSaving(false);\n }\n },\n [path, load],\n );\n\n return { settings, isLoading, error, save, isSaving, saveError };\n}\n","/**\n * Browser helpers for app pages.\n *\n * App bundles get react, react-dom and this SDK from the shell's import map and\n * bundle everything else themselves — so without these here, every app would\n * reimplement clipboard handling and CSV escaping, and get the edge cases wrong\n * in its own way.\n */\n\n/**\n * Copy text to the clipboard.\n *\n * Returns `false` instead of throwing when the clipboard is unavailable (non\n * secure context, permission refused) so the caller can render inline feedback.\n * No `document.execCommand('copy')` fallback: it is deprecated, and the shell\n * only ever runs on https or localhost, both secure contexts.\n */\nexport async function copyToClipboard(text: string): Promise<boolean> {\n if (!navigator?.clipboard || !window.isSecureContext) return false;\n try {\n await navigator.clipboard.writeText(text);\n return true;\n } catch {\n return false;\n }\n}\n\n/** Trigger a browser download of a Blob via a throwaway object URL + `<a>` click. */\nexport function downloadBlob(blob: Blob, filename: string): void {\n const url = URL.createObjectURL(blob);\n const a = document.createElement('a');\n a.href = url;\n a.download = filename;\n document.body.appendChild(a);\n a.click();\n a.remove();\n URL.revokeObjectURL(url);\n}\n\n/** Escape one CSV field per RFC 4180: quote it, and double any embedded quote,\n * whenever it contains a comma, a quote, or a line break. */\nfunction escapeCsvField(value: string): string {\n return /[\",\\r\\n]/.test(value) ? `\"${value.replace(/\"/g, '\"\"')}\"` : value;\n}\n\n/** Serialize rows (header included) into an RFC 4180 CSV string. */\nexport function toCsv(rows: string[][]): string {\n return rows.map((row) => row.map(escapeCsvField).join(',')).join('\\r\\n');\n}\n\n/** UTF-8 byte order mark. */\nconst BOM = '\\uFEFF';\n\n/**\n * Serialize + download in one call.\n *\n * The BOM is the whole reason this helper exists: without it Excel on Windows\n * reads the file as latin-1 and mangles every accented character.\n */\nexport function downloadCsv(rows: string[][], filename: string): void {\n const blob = new Blob([`${BOM}${toCsv(rows)}`], { type: 'text/csv;charset=utf-8' });\n downloadBlob(blob, filename);\n}\n","/**\n * Design system components exported by @apotech-os/ui-sdk.\n *\n * These are minimal self-contained copies of the shell's component library.\n * They use the same Tailwind utility classes as the shell — Tailwind classes\n * are plain strings and work without any build step when the shell's stylesheet\n * is loaded (which it is, since these pages run inside the shell).\n *\n * Strategy note:\n * - Not imported from apps/web (would create a circular dep pkg → app).\n * - Copied/adapted here to keep the SDK self-contained and publishable.\n * - The exhaustive component inventory is tracked in #75.\n */\n\nimport { type VariantProps, cva } from 'class-variance-authority';\nimport * as React from 'react';\nimport { cn } from './cn';\nimport { copyToClipboard } from './utils';\n\n// ---------------------------------------------------------------------------\n// Button\n// ---------------------------------------------------------------------------\n\nconst buttonVariants = cva(\n 'inline-flex cursor-pointer items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-50',\n {\n variants: {\n variant: {\n default: 'bg-primary text-primary-foreground hover:bg-primary/90',\n secondary: 'bg-secondary text-secondary-foreground hover:bg-secondary/80',\n outline: 'border border-input bg-background hover:bg-accent hover:text-accent-foreground',\n ghost: 'hover:bg-accent hover:text-accent-foreground',\n destructive: 'bg-destructive text-white hover:bg-destructive/90',\n },\n size: {\n default: 'h-9 px-4 py-2',\n sm: 'h-8 rounded-md px-3 text-xs',\n lg: 'h-10 rounded-md px-6',\n icon: 'h-9 w-9',\n },\n },\n defaultVariants: { variant: 'default', size: 'default' },\n },\n);\n\nexport interface ButtonProps\n extends React.ButtonHTMLAttributes<HTMLButtonElement>, VariantProps<typeof buttonVariants> {}\n\nexport const Button = React.forwardRef<HTMLButtonElement, ButtonProps>(\n ({ className, variant, size, ...props }, ref) => (\n <button ref={ref} className={cn(buttonVariants({ variant, size, className }))} {...props} />\n ),\n);\nButton.displayName = 'Button';\n\n// ---------------------------------------------------------------------------\n// Badge\n// ---------------------------------------------------------------------------\n\nconst badgeVariants = cva(\n 'inline-flex items-center gap-1.5 rounded-full border px-2 py-0.5 text-xs font-medium whitespace-nowrap',\n {\n variants: {\n variant: {\n neutral: 'border-border bg-muted text-muted-foreground',\n brand: 'border-primary/20 bg-primary/10 text-primary',\n success: 'border-status-success/25 bg-status-success/10 text-status-success',\n warning: 'border-status-pending/30 bg-status-pending/10 text-status-pending',\n danger: 'border-status-blocked/25 bg-status-blocked/10 text-status-blocked',\n info: 'border-status-info/25 bg-status-info/10 text-status-info',\n outline: 'border-border bg-transparent text-muted-foreground',\n },\n },\n defaultVariants: { variant: 'neutral' },\n },\n);\n\nexport interface BadgeProps\n extends React.HTMLAttributes<HTMLSpanElement>, VariantProps<typeof badgeVariants> {\n dot?: boolean;\n}\n\nexport function Badge({ className, variant, dot, children, ...props }: BadgeProps) {\n return (\n <span className={cn(badgeVariants({ variant }), className)} {...props}>\n {dot && <span className=\"size-1.5 rounded-full bg-current\" />}\n {children}\n </span>\n );\n}\n\n// ---------------------------------------------------------------------------\n// Card\n// ---------------------------------------------------------------------------\n\nexport function Card({ className, ...props }: React.HTMLAttributes<HTMLDivElement>) {\n return (\n <div\n className={cn('rounded-xl border bg-card text-card-foreground shadow-sm', className)}\n {...props}\n />\n );\n}\n\nexport function CardHeader({ className, ...props }: React.HTMLAttributes<HTMLDivElement>) {\n return <div className={cn('flex flex-col space-y-1.5 p-6', className)} {...props} />;\n}\n\nexport function CardTitle({ className, ...props }: React.HTMLAttributes<HTMLHeadingElement>) {\n return (\n <h3 className={cn('text-lg font-semibold leading-none tracking-tight', className)} {...props} />\n );\n}\n\nexport function CardContent({ className, ...props }: React.HTMLAttributes<HTMLDivElement>) {\n return <div className={cn('p-6 pt-0', className)} {...props} />;\n}\n\n// ---------------------------------------------------------------------------\n// Input\n// ---------------------------------------------------------------------------\n\nexport const Input = React.forwardRef<\n HTMLInputElement,\n React.InputHTMLAttributes<HTMLInputElement>\n>(({ className, type, ...props }, ref) => (\n <input\n type={type}\n className={cn(\n 'flex h-9 w-full rounded-md border border-input bg-transparent px-3 py-1 text-sm shadow-sm transition-colors file:border-0 file:bg-transparent file:text-sm file:font-medium placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:cursor-not-allowed disabled:opacity-50',\n className,\n )}\n ref={ref}\n {...props}\n />\n));\nInput.displayName = 'Input';\n\n// ---------------------------------------------------------------------------\n// Table\n// ---------------------------------------------------------------------------\n\nexport function Table({ className, ...props }: React.HTMLAttributes<HTMLTableElement>) {\n return <table className={cn('w-full text-sm', className)} {...props} />;\n}\n\nexport function TableHeader({\n className,\n ...props\n}: React.HTMLAttributes<HTMLTableSectionElement>) {\n return <thead className={cn('[&_tr]:border-b', className)} {...props} />;\n}\n\nexport function TableBody({ className, ...props }: React.HTMLAttributes<HTMLTableSectionElement>) {\n return <tbody className={cn('[&_tr:last-child]:border-0', className)} {...props} />;\n}\n\nexport function TableRow({ className, ...props }: React.HTMLAttributes<HTMLTableRowElement>) {\n return (\n <tr\n className={cn(\n 'border-b transition-colors hover:bg-muted/50 data-[state=selected]:bg-muted',\n className,\n )}\n {...props}\n />\n );\n}\n\nexport function TableHead({ className, ...props }: React.ThHTMLAttributes<HTMLTableCellElement>) {\n return (\n <th\n className={cn(\n 'h-10 px-4 text-left align-middle text-xs font-medium text-muted-foreground',\n className,\n )}\n {...props}\n />\n );\n}\n\nexport function TableCell({ className, ...props }: React.TdHTMLAttributes<HTMLTableCellElement>) {\n return <td className={cn('p-4 align-middle', className)} {...props} />;\n}\n\n// ---------------------------------------------------------------------------\n// Select\n// ---------------------------------------------------------------------------\n\nexport interface SelectProps extends React.SelectHTMLAttributes<HTMLSelectElement> {}\n\nexport const Select = React.forwardRef<HTMLSelectElement, SelectProps>(\n ({ className, children, ...props }, ref) => (\n <select\n ref={ref}\n className={cn(\n 'flex h-9 w-full rounded-md border border-input bg-transparent px-3 py-1 text-sm shadow-sm transition-colors focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:cursor-not-allowed disabled:opacity-50',\n className,\n )}\n {...props}\n >\n {children}\n </select>\n ),\n);\nSelect.displayName = 'Select';\n\n// ---------------------------------------------------------------------------\n// Tabs\n// ---------------------------------------------------------------------------\n\ninterface TabsContextValue {\n value: string;\n setValue: (v: string) => void;\n}\n\nconst TabsContext = React.createContext<TabsContextValue | null>(null);\n\nfunction useTabsContext(): TabsContextValue {\n const ctx = React.useContext(TabsContext);\n if (!ctx) throw new Error('Tabs sub-component must be used within <Tabs>');\n return ctx;\n}\n\nexport interface TabsProps {\n defaultValue?: string;\n value?: string;\n onValueChange?: (v: string) => void;\n className?: string;\n children: React.ReactNode;\n}\n\nexport function Tabs({ defaultValue, value, onValueChange, className, children }: TabsProps) {\n const [internal, setInternal] = React.useState(defaultValue ?? '');\n const current = value ?? internal;\n const setValue = (v: string) => {\n setInternal(v);\n onValueChange?.(v);\n };\n return (\n <TabsContext.Provider value={{ value: current, setValue }}>\n <div className={className}>{children}</div>\n </TabsContext.Provider>\n );\n}\n\nexport function TabsList({\n className,\n children,\n}: {\n className?: string;\n children: React.ReactNode;\n}) {\n return (\n <div className={cn('inline-flex items-center gap-1 rounded-lg bg-muted p-1', className)}>\n {children}\n </div>\n );\n}\n\nexport function TabsTrigger({\n value,\n className,\n children,\n}: {\n value: string;\n className?: string;\n children: React.ReactNode;\n}) {\n const { value: current, setValue } = useTabsContext();\n const active = current === value;\n return (\n <button\n type=\"button\"\n onClick={() => setValue(value)}\n className={cn(\n 'rounded-md px-3 py-1.5 text-sm font-medium transition-colors',\n active\n ? 'bg-card text-foreground shadow-sm'\n : 'text-muted-foreground hover:text-foreground',\n className,\n )}\n >\n {children}\n </button>\n );\n}\n\nexport function TabsContent({\n value,\n className,\n children,\n}: {\n value: string;\n className?: string;\n children: React.ReactNode;\n}) {\n const { value: current } = useTabsContext();\n if (current !== value) return null;\n return <div className={className}>{children}</div>;\n}\n\n// ---------------------------------------------------------------------------\n// Modal (controlled, no Radix)\n// ---------------------------------------------------------------------------\n\nexport interface ModalProps {\n open: boolean;\n onClose: () => void;\n title?: React.ReactNode;\n children: React.ReactNode;\n className?: string;\n}\n\nexport function Modal({ open, onClose, title, children, className }: ModalProps) {\n if (!open) return null;\n return (\n <div className=\"fixed inset-0 z-50 flex items-center justify-center p-4\">\n <button\n type=\"button\"\n aria-label=\"Close\"\n className=\"absolute inset-0 cursor-default bg-foreground/40\"\n onClick={onClose}\n />\n <div\n role=\"dialog\"\n aria-modal\n className={cn(\n 'relative z-10 w-full max-w-md rounded-xl border bg-card p-5 shadow-lg',\n className,\n )}\n >\n {title && <h2 className=\"mb-3 text-base font-semibold\">{title}</h2>}\n {children}\n </div>\n </div>\n );\n}\n\n// ---------------------------------------------------------------------------\n// Spinner\n// ---------------------------------------------------------------------------\n\nexport interface SpinnerProps {\n className?: string;\n size?: 'sm' | 'md' | 'lg';\n}\n\nconst spinnerSizes = { sm: 'size-4', md: 'size-6', lg: 'size-8' };\n\nexport function Spinner({ className, size = 'md' }: SpinnerProps) {\n return (\n <svg\n className={cn('animate-spin text-muted-foreground', spinnerSizes[size], className)}\n xmlns=\"http://www.w3.org/2000/svg\"\n fill=\"none\"\n viewBox=\"0 0 24 24\"\n aria-label=\"Loading\"\n role=\"status\"\n >\n <circle className=\"opacity-25\" cx=\"12\" cy=\"12\" r=\"10\" stroke=\"currentColor\" strokeWidth=\"4\" />\n <path\n className=\"opacity-75\"\n fill=\"currentColor\"\n d=\"M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4z\"\n />\n </svg>\n );\n}\n\n// ---------------------------------------------------------------------------\n// Link\n// ---------------------------------------------------------------------------\n\nexport interface LinkProps extends React.AnchorHTMLAttributes<HTMLAnchorElement> {\n variant?: 'default' | 'muted';\n}\n\nexport const Link = React.forwardRef<HTMLAnchorElement, LinkProps>(\n ({ className, variant = 'default', ...props }, ref) => (\n <a\n ref={ref}\n className={cn(\n 'underline-offset-4 hover:underline focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring',\n variant === 'default' ? 'text-primary' : 'text-muted-foreground',\n className,\n )}\n {...props}\n />\n ),\n);\nLink.displayName = 'Link';\n\n// ---------------------------------------------------------------------------\n// Switch\n// ---------------------------------------------------------------------------\n\nexport interface SwitchProps {\n checked?: boolean;\n onCheckedChange?: (checked: boolean) => void;\n disabled?: boolean;\n className?: string;\n 'aria-label'?: string;\n}\n\nexport function Switch({\n checked = false,\n onCheckedChange,\n disabled,\n className,\n ...props\n}: SwitchProps) {\n return (\n <button\n type=\"button\"\n role=\"switch\"\n aria-checked={checked}\n disabled={disabled}\n onClick={() => onCheckedChange?.(!checked)}\n className={cn(\n 'relative inline-flex h-5 w-9 shrink-0 cursor-pointer items-center rounded-full transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring disabled:cursor-not-allowed disabled:opacity-50',\n checked ? 'bg-primary' : 'bg-input',\n className,\n )}\n {...props}\n >\n <span\n className={cn(\n 'inline-block size-4 transform rounded-full bg-white shadow transition-transform',\n checked ? 'translate-x-4' : 'translate-x-0.5',\n )}\n />\n </button>\n );\n}\n\n// ---------------------------------------------------------------------------\n// DateRangePicker\n// ---------------------------------------------------------------------------\n\nexport interface DateRange {\n from: string;\n to: string;\n}\n\nexport interface DateRangePickerProps {\n value: DateRange;\n onChange: (range: DateRange) => void;\n className?: string;\n disabled?: boolean;\n}\n\n/** Minimal controlled date-range picker using two native date inputs. */\nexport function DateRangePicker({ value, onChange, className, disabled }: DateRangePickerProps) {\n return (\n <div className={cn('flex items-center gap-2', className)}>\n <input\n type=\"date\"\n disabled={disabled}\n value={value.from}\n max={value.to || undefined}\n onChange={(e) => onChange({ ...value, from: e.target.value })}\n className=\"flex h-9 rounded-md border border-input bg-transparent px-3 py-1 text-sm shadow-sm transition-colors focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:cursor-not-allowed disabled:opacity-50\"\n />\n <span className=\"text-muted-foreground text-sm\">→</span>\n <input\n type=\"date\"\n disabled={disabled}\n value={value.to}\n min={value.from || undefined}\n onChange={(e) => onChange({ ...value, to: e.target.value })}\n className=\"flex h-9 rounded-md border border-input bg-transparent px-3 py-1 text-sm shadow-sm transition-colors focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:cursor-not-allowed disabled:opacity-50\"\n />\n </div>\n );\n}\n\n// ---------------------------------------------------------------------------\n// Icons\n//\n// Inline SVGs rather than a lucide-react dependency: the SDK is loaded through\n// the shell's import map as a single vendor chunk, so a dependency here inflates\n// every app page. Same precedent as Spinner above.\n// ---------------------------------------------------------------------------\n\nfunction IconX({ className }: { className?: string }) {\n return (\n <svg\n className={className}\n xmlns=\"http://www.w3.org/2000/svg\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"2\"\n strokeLinecap=\"round\"\n aria-hidden=\"true\"\n >\n <path d=\"M18 6 6 18M6 6l12 12\" />\n </svg>\n );\n}\n\nfunction IconCopy({ className }: { className?: string }) {\n return (\n <svg\n className={className}\n xmlns=\"http://www.w3.org/2000/svg\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"2\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n aria-hidden=\"true\"\n >\n <rect width=\"14\" height=\"14\" x=\"8\" y=\"8\" rx=\"2\" ry=\"2\" />\n <path d=\"M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2\" />\n </svg>\n );\n}\n\nfunction IconCheck({ className }: { className?: string }) {\n return (\n <svg\n className={className}\n xmlns=\"http://www.w3.org/2000/svg\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"2\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n aria-hidden=\"true\"\n >\n <path d=\"M20 6 9 17l-5-5\" />\n </svg>\n );\n}\n\n// ---------------------------------------------------------------------------\n// Textarea\n// ---------------------------------------------------------------------------\n\nexport type TextareaProps = React.TextareaHTMLAttributes<HTMLTextAreaElement>;\n\nexport const Textarea = React.forwardRef<HTMLTextAreaElement, TextareaProps>(\n function Textarea({ className, ...props }, ref) {\n return (\n <textarea\n ref={ref}\n className={cn(\n 'flex min-h-20 w-full rounded-md border border-input bg-transparent px-3 py-2 text-sm shadow-sm transition-colors placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:cursor-not-allowed disabled:opacity-50',\n className,\n )}\n {...props}\n />\n );\n },\n);\n\n// ---------------------------------------------------------------------------\n// Checkbox\n// ---------------------------------------------------------------------------\n\nexport interface CheckboxProps\n extends Omit<React.InputHTMLAttributes<HTMLInputElement>, 'type' | 'onChange'> {\n checked?: boolean;\n /** Preferred over onChange — receives the boolean directly. */\n onCheckedChange?: (checked: boolean) => void;\n label?: React.ReactNode;\n}\n\nexport const Checkbox = React.forwardRef<HTMLInputElement, CheckboxProps>(\n function Checkbox({ className, label, onCheckedChange, ...props }, ref) {\n const input = (\n <input\n ref={ref}\n type=\"checkbox\"\n className={cn(\n 'size-4 shrink-0 cursor-pointer rounded border-input accent-primary disabled:cursor-not-allowed disabled:opacity-50',\n className,\n )}\n onChange={(e) => onCheckedChange?.(e.target.checked)}\n {...props}\n />\n );\n if (!label) return input;\n return (\n <label className=\"inline-flex cursor-pointer items-center gap-2 text-sm\">\n {input}\n <span>{label}</span>\n </label>\n );\n },\n);\n\n// ---------------------------------------------------------------------------\n// SidePanel\n// ---------------------------------------------------------------------------\n\nexport interface SidePanelProps {\n open: boolean;\n onClose: () => void;\n title?: React.ReactNode;\n description?: React.ReactNode;\n children: React.ReactNode;\n className?: string;\n}\n\n/**\n * Blocking slide-over — reach for it when a task has more fields than a `Modal`\n * can show without an inner scrollbar. Full height, so the body scrolls once and\n * a footer can stay pinned; `Modal` centres a box and does no height management.\n *\n * Children are laid out in a flex column filling the panel: put the scrollable\n * region in a `min-h-0 flex-1 overflow-y-auto` child and the footer after it.\n *\n * NOTE: no focus management. Autofocus the primary action yourself.\n */\nexport function SidePanel({\n open,\n onClose,\n title,\n description,\n children,\n className,\n}: SidePanelProps) {\n // Escape closes. A panel that covers the viewport makes a missing keyboard\n // exit far more noticeable than it is on a centred Modal.\n React.useEffect(() => {\n if (!open) return;\n const onKeyDown = (e: KeyboardEvent) => {\n if (e.key === 'Escape') onClose();\n };\n window.addEventListener('keydown', onKeyDown);\n return () => window.removeEventListener('keydown', onKeyDown);\n }, [open, onClose]);\n\n if (!open) return null;\n return (\n <div className=\"fixed inset-0 z-50\">\n <button\n type=\"button\"\n aria-label=\"Fermer\"\n className=\"absolute inset-0 cursor-default bg-foreground/40\"\n onClick={onClose}\n />\n <aside\n role=\"dialog\"\n aria-modal\n className={cn(\n 'absolute inset-y-0 right-0 flex w-full max-w-lg flex-col border-l bg-card shadow-xl',\n className,\n )}\n >\n <header className=\"flex shrink-0 items-start gap-3 border-b px-5 py-4\">\n <div className=\"min-w-0 flex-1\">\n {title && <h2 className=\"text-base font-semibold\">{title}</h2>}\n {description && <p className=\"mt-0.5 text-xs text-muted-foreground\">{description}</p>}\n </div>\n <button\n type=\"button\"\n aria-label=\"Fermer\"\n className=\"-mr-1 shrink-0 rounded-md p-1 text-muted-foreground hover:bg-accent hover:text-foreground\"\n onClick={onClose}\n >\n <IconX className=\"size-4\" />\n </button>\n </header>\n <div className=\"flex min-h-0 flex-1 flex-col px-5 py-4\">{children}</div>\n </aside>\n </div>\n );\n}\n\n// ---------------------------------------------------------------------------\n// CopyButton\n// ---------------------------------------------------------------------------\n\nexport interface CopyButtonProps {\n value: string;\n label?: string;\n copiedLabel?: string;\n variant?: ButtonProps['variant'];\n size?: ButtonProps['size'];\n className?: string;\n}\n\n/** How long the confirmation stays up before reverting. */\nconst COPY_FEEDBACK_MS = 2000;\n\n/**\n * Copy-to-clipboard button with inline feedback. On failure it says so rather\n * than silently doing nothing — keep the copyable text selectable so manual\n * copy stays the fallback.\n */\nexport function CopyButton({\n value,\n label = 'Copier',\n copiedLabel = 'Copié',\n variant = 'outline',\n size = 'sm',\n className,\n}: CopyButtonProps) {\n const [state, setState] = React.useState<'idle' | 'copied' | 'error'>('idle');\n const timeout = React.useRef<ReturnType<typeof setTimeout> | undefined>(undefined);\n\n // Held in a ref and cleared on unmount: the panel can close mid-feedback.\n React.useEffect(() => () => clearTimeout(timeout.current), []);\n\n async function copy() {\n const ok = await copyToClipboard(value);\n setState(ok ? 'copied' : 'error');\n clearTimeout(timeout.current);\n timeout.current = setTimeout(() => setState('idle'), COPY_FEEDBACK_MS);\n }\n\n return (\n <Button\n type=\"button\"\n variant={variant}\n size={size}\n className={className}\n onClick={() => void copy()}\n >\n {state === 'copied' ? (\n <IconCheck className=\"size-3.5\" />\n ) : (\n <IconCopy className=\"size-3.5\" />\n )}\n <span aria-live=\"polite\" className={state === 'error' ? 'text-destructive' : undefined}>\n {state === 'copied' ? copiedLabel : state === 'error' ? 'Copie impossible' : label}\n </span>\n </Button>\n );\n}\n\n// ---------------------------------------------------------------------------\n// Popover\n// ---------------------------------------------------------------------------\n\nexport interface PopoverProps {\n open: boolean;\n onOpenChange: (open: boolean) => void;\n trigger: React.ReactNode;\n children: React.ReactNode;\n align?: 'start' | 'end';\n className?: string;\n}\n\n/** Anchored panel. Controlled — the caller owns `open`. Closes on outside click\n * and Escape, which is what a filter pill needs and a Modal is too heavy for. */\nexport function Popover({\n open,\n onOpenChange,\n trigger,\n children,\n align = 'start',\n className,\n}: PopoverProps) {\n const root = React.useRef<HTMLDivElement>(null);\n\n React.useEffect(() => {\n if (!open) return;\n const onPointerDown = (e: MouseEvent) => {\n if (!root.current?.contains(e.target as Node)) onOpenChange(false);\n };\n const onKeyDown = (e: KeyboardEvent) => {\n if (e.key === 'Escape') onOpenChange(false);\n };\n document.addEventListener('mousedown', onPointerDown);\n document.addEventListener('keydown', onKeyDown);\n return () => {\n document.removeEventListener('mousedown', onPointerDown);\n document.removeEventListener('keydown', onKeyDown);\n };\n }, [open, onOpenChange]);\n\n return (\n <div ref={root} className=\"relative inline-block\">\n <button type=\"button\" aria-expanded={open} onClick={() => onOpenChange(!open)}>\n {trigger}\n </button>\n {open && (\n <div\n className={cn(\n 'absolute z-40 mt-1 min-w-48 rounded-md border bg-card p-2 shadow-lg',\n align === 'end' ? 'right-0' : 'left-0',\n className,\n )}\n >\n {children}\n </div>\n )}\n </div>\n );\n}\n\n// ---------------------------------------------------------------------------\n// DropdownMenu\n// ---------------------------------------------------------------------------\n\nexport interface DropdownMenuItem {\n label: React.ReactNode;\n onSelect: () => void;\n disabled?: boolean;\n destructive?: boolean;\n}\n\nexport interface DropdownMenuProps {\n trigger: React.ReactNode;\n items: DropdownMenuItem[];\n align?: 'start' | 'end';\n className?: string;\n}\n\n/** Uncontrolled menu built on Popover. Selecting an item closes it. */\nexport function DropdownMenu({ trigger, items, align = 'end', className }: DropdownMenuProps) {\n const [open, setOpen] = React.useState(false);\n return (\n <Popover\n open={open}\n onOpenChange={setOpen}\n trigger={trigger}\n align={align}\n className={cn('p-1', className)}\n >\n <div role=\"menu\" className=\"flex flex-col\">\n {items.map((item, i) => (\n <button\n key={i}\n type=\"button\"\n role=\"menuitem\"\n disabled={item.disabled}\n className={cn(\n 'cursor-pointer rounded px-2 py-1.5 text-left text-sm hover:bg-accent disabled:pointer-events-none disabled:opacity-50',\n item.destructive && 'text-destructive',\n )}\n onClick={() => {\n setOpen(false);\n item.onSelect();\n }}\n >\n {item.label}\n </button>\n ))}\n </div>\n </Popover>\n );\n}\n"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@apotech-os/ui-sdk",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.8.0",
|
|
4
|
+
"uiContractVersion": 1,
|
|
4
5
|
"type": "module",
|
|
5
6
|
"main": "./dist/index.cjs",
|
|
6
7
|
"module": "./dist/index.js",
|
|
@@ -34,7 +35,8 @@
|
|
|
34
35
|
"dependencies": {
|
|
35
36
|
"class-variance-authority": "^0.7.1",
|
|
36
37
|
"clsx": "^2.1.1",
|
|
37
|
-
"tailwind-merge": "^3.3.0"
|
|
38
|
+
"tailwind-merge": "^3.3.0",
|
|
39
|
+
"@apotech-os/app-kit": "0.8.0"
|
|
38
40
|
},
|
|
39
41
|
"devDependencies": {
|
|
40
42
|
"@testing-library/dom": "^10.4.1",
|