@opencxh/ui-kit 3.153.0 → 3.154.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 +1 -1
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.cjs","sources":["../src/utils/cn.ts","../src/utils/useAnchoredPosition.ts","../src/utils/identity.ts","../src/utils/catTone.ts","../src/utils/text.ts","../src/meeting/MeetingGrid.tsx","../src/meeting/ParticipantTile.tsx","../src/meeting/VideoSurface.tsx","../src/action/Button.tsx","../src/action/ButtonGroup.tsx","../src/content/Icon.tsx","../src/overlays/Popover.tsx","../src/action/FilterChip.tsx","../src/action/Link.tsx","../src/action/SegmentedToggle.tsx","../src/action/SplitButton.tsx","../src/input/Checkbox.tsx","../src/typography/Text.tsx","../src/input/ImageField.tsx","../src/input/DatePicker.tsx","../src/input/Select.tsx","../src/input/TextField.tsx","../src/input/FolderSelect.tsx","../src/input/SearchableTextField.tsx","../src/input/SearchField.tsx","../src/input/Switch.tsx","../src/overlays/Dropdown.tsx","../src/content/PageToolbar.tsx","../src/content/Table.tsx","../src/navigation/Tabs.tsx","../src/overlays/Modal.tsx","../src/input/StorageInput.tsx","../src/input/TextArea.tsx","../src/forms/autofill.ts","../src/forms/Form.tsx","../src/overlays/ConfirmDialog.tsx","../src/feedback/Badge.tsx","../src/feedback/ContentLoading.tsx","../src/feedback/EmptyState.tsx","../src/feedback/Kbd.tsx","../src/feedback/ProgressBar.tsx","../src/feedback/Spinner.tsx","../src/feedback/StatusDot.tsx","../src/feedback/StepIndicator.tsx","../src/content/RichText.tsx","../src/content/ArtifactView.tsx","../src/content/AssistantCard.tsx","../src/content/Avatar.tsx","../src/content/AvatarStack.tsx","../src/content/ChannelBadge.tsx","../src/content/Image.tsx","../src/content/List.tsx","../src/content/MessageBubble.tsx","../src/content/KpiCard.tsx","../src/content/PageHeader.tsx","../src/content/Page.tsx","../src/content/SectionCaption.tsx","../src/content/SectionDivider.tsx","../src/content/SettingsPage.tsx","../src/content/SettingsRow.tsx","../src/content/SourceChip.tsx","../src/content/tableColumns.tsx","../src/content/View.tsx","../src/navigation/Sidebar.tsx","../src/typography/Heading.tsx","../src/command-palette/CommandPalette.tsx","../src/primitives/Box.tsx","../src/primitives/Card.tsx","../src/federated-resource/index.tsx","../src/error-boundary/index.tsx"],"sourcesContent":["import { clsx, type ClassValue } from 'clsx';\n\n/**\n * Utility function for combining class names\n * Combines clsx for conditional classes with Tailwind merge for deduplication\n */\nexport function cn(...inputs: ClassValue[]) {\n return clsx(inputs);\n}\n\n/**\n * Utility for creating variant-based class combinations\n */\nexport function createVariants<T extends Record<string, Record<string, string>>>(\n variants: T\n) {\n return (variant: keyof T, value: keyof T[keyof T]) => {\n return variants[variant]?.[value] || '';\n };\n}\n\n/**\n * Utility for creating size-based class combinations\n */\nexport function createSizes<T extends Record<string, string>>(sizes: T) {\n return (size: keyof T) => sizes[size] || '';\n} ","import { useLayoutEffect, useState, type CSSProperties, type RefObject } from \"react\";\n\nexport interface AnchoredPositionOptions {\n /** Gap between the anchor and the panel, in px. */\n gap?: number;\n /** Match the panel's width to the anchor — what a select wants, a menu does not. */\n matchWidth?: boolean;\n /** Preferred side. Flips automatically when there is no room. */\n placement?: \"bottom-start\" | \"bottom-end\" | \"top-start\" | \"top-end\";\n}\n\n/**\n * Position a floating panel against its trigger, in viewport coordinates.\n *\n * Two problems this solves, both of which a plain `absolute` panel has:\n * an ancestor with `overflow-hidden` (a bordered form panel, a scroll area)\n * clips the panel, and a trigger near the bottom of the window opens a panel\n * that runs off-screen. Fixed coordinates escape every ancestor, and the\n * placement flips upward when the space below is too small.\n *\n * Recomputes on scroll and resize while open, so the panel tracks its trigger\n * instead of detaching when the page moves under it.\n */\nexport function useAnchoredPosition(\n open: boolean,\n anchorRef: RefObject<HTMLElement | null>,\n { gap = 6, matchWidth = false, placement = \"bottom-start\" }: AnchoredPositionOptions = {}\n): CSSProperties {\n const [style, setStyle] = useState<CSSProperties>({});\n\n // Layout effect, not effect: measure and place before the browser paints,\n // otherwise the panel is visible at the wrong spot for a frame.\n useLayoutEffect(() => {\n if (!open) return;\n\n const place = () => {\n const anchor = anchorRef.current;\n if (!anchor) return;\n\n const rect = anchor.getBoundingClientRect();\n const spaceBelow = window.innerHeight - rect.bottom;\n const spaceAbove = rect.top;\n\n // Flip up only when below genuinely cannot hold a usable panel and above\n // has more room — flipping into an equally cramped space helps nobody.\n const wantsTop = placement.startsWith(\"top\");\n const flip = wantsTop\n ? spaceAbove < 200 && spaceBelow > spaceAbove\n : spaceBelow < 200 && spaceAbove > spaceBelow;\n const onTop = wantsTop !== flip;\n\n const next: CSSProperties = { position: \"fixed\" };\n\n if (onTop) {\n next.bottom = window.innerHeight - rect.top + gap;\n next.maxHeight = Math.max(120, spaceAbove - gap * 2);\n } else {\n next.top = rect.bottom + gap;\n next.maxHeight = Math.max(120, spaceBelow - gap * 2);\n }\n\n if (placement.endsWith(\"end\")) next.right = window.innerWidth - rect.right;\n else next.left = rect.left;\n\n if (matchWidth) next.width = rect.width;\n\n setStyle(next);\n };\n\n place();\n // `true` captures scrolls on any ancestor, not just the window.\n window.addEventListener(\"scroll\", place, true);\n window.addEventListener(\"resize\", place);\n return () => {\n window.removeEventListener(\"scroll\", place, true);\n window.removeEventListener(\"resize\", place);\n };\n }, [open, anchorRef, gap, matchWidth, placement]);\n\n return style;\n}\n","/**\n * Deterministic colour for a thing that has a name but no status.\n *\n * The rule this exists to enforce: the same name gets the same colour\n * everywhere in the product. Every surface that used to pick a plate colour did\n * it locally — an index in a list, a hash of its own, or a fixed neutral — so\n * one person could be blue in the inbox and grey on a task, and the colour\n * carried no information at all.\n *\n * The palette is the `--color-cat-*` categorical set, which the design system\n * defines for exactly this: equal chroma and lightness, so no entry outranks\n * another, and dark mode is handled by the tokens rather than here.\n */\n\n/** How many `--color-cat-N` entries the design system defines. */\nexport const IDENTITY_TONE_COUNT = 5;\n\nexport type IdentityTone = 1 | 2 | 3 | 4 | 5;\n\n/**\n * FNV-1a. Small, stable across runs and platforms, and well spread for short\n * strings — `Math.random` would break the whole point, and summing char codes\n * collides badly on names that are anagrams (\"Bram\"/\"Marb\") or differ only in\n * order (\"Team A\"/\"A Team\").\n */\nfunction hash(seed: string): number {\n let h = 0x811c9dc5;\n for (let i = 0; i < seed.length; i++) {\n h ^= seed.charCodeAt(i);\n h = Math.imul(h, 0x01000193);\n }\n return h >>> 0;\n}\n\n/**\n * Normalised so that the same identity written differently still lands on the\n * same colour: casing and surrounding whitespace never distinguish two names.\n */\nexport function identityTone(seed: string | undefined | null): IdentityTone {\n const key = (seed ?? \"\").trim().toLowerCase();\n if (!key) return 1;\n return ((hash(key) % IDENTITY_TONE_COUNT) + 1) as IdentityTone;\n}\n\n/**\n * Whole class names, not interpolated fragments: Tailwind scans source text, so\n * `bg-cat-${n}-soft` would compile to nothing and the plate would come out\n * transparent.\n */\nconst PLATE: Record<IdentityTone, string> = {\n 1: \"bg-cat-1-soft text-cat-1-fg\",\n 2: \"bg-cat-2-soft text-cat-2-fg\",\n 3: \"bg-cat-3-soft text-cat-3-fg\",\n 4: \"bg-cat-4-soft text-cat-4-fg\",\n 5: \"bg-cat-5-soft text-cat-5-fg\",\n};\n\nconst SOLID: Record<IdentityTone, string> = {\n 1: \"bg-cat-1\",\n 2: \"bg-cat-2\",\n 3: \"bg-cat-3\",\n 4: \"bg-cat-4\",\n 5: \"bg-cat-5\",\n};\n\n/** Wash + readable mark, for a plate that holds a monogram or a glyph. */\nexport function identityPlateClass(seed: string | undefined | null): string {\n return PLATE[identityTone(seed)];\n}\n\n/** The solid colour, for a dot or a rule. */\nexport function identityDotClass(seed: string | undefined | null): string {\n return SOLID[identityTone(seed)];\n}\n","/** The categorical set — identity without status. See --color-cat-*. */\nexport type CatTone = \"cat-1\" | \"cat-2\" | \"cat-3\" | \"cat-4\" | \"cat-5\";\n\nconst TONES: CatTone[] = [\"cat-1\", \"cat-2\", \"cat-3\", \"cat-4\", \"cat-5\"];\n\n/**\n * A stable colour for a thing that has an identity but no state — a knowledge\n * base, an inbox, a team, a transcript speaker.\n *\n * Derived from the id, so the colour survives reloads and is the same for every\n * user. Storing one would mean a column per entity that wants a dot; a hash\n * gets the same result for free, and the categorical tokens are equal-weight by\n * construction so no entry can accidentally outrank another.\n */\nexport function catTone(id: string): CatTone {\n let hash = 0;\n for (let i = 0; i < id.length; i++) hash = (hash * 31 + id.charCodeAt(i)) >>> 0;\n return TONES[hash % TONES.length];\n}\n","/**\n * Coerce an unknown value to text.\n *\n * Every input component in this kit declares its `value` as `string`, and every\n * one of them is fed straight out of form data, which is `any`. A field whose\n * entity type is numeric therefore arrives as a number — `eylo-voip`'s time\n * rules do exactly that (`interval?: number`, `days?: number[]`) — and the two\n * failure modes are both silent from the type system's side:\n *\n * - a hard `TypeError: (…).trim is not a function` the moment anything calls a\n * string method on it;\n * - a comparison that simply never matches, because `1 === \"1\"` is false, so a\n * stored option renders as unselected with no error at all.\n *\n * `null` and `undefined` become `\"\"` so callers can treat \"absent\" and \"empty\"\n * alike, which is what a text input does anyway.\n */\nexport const text = (value: unknown): string => (value == null ? \"\" : String(value));\n\n/** {@link text} folded to a comparable key: trimmed and lower-cased. */\nexport const normalizeText = (value: unknown): string => text(value).trim().toLowerCase();\n","import type { ReactNode } from \"react\";\nimport { cn } from \"../utils/cn\";\n\nexport interface MeetingGridProps {\n tiles: ReactNode[];\n pinned?: ReactNode;\n className?: string;\n}\n\n/**\n * Layout primitive for meeting views. When `pinned` is provided it gets the\n * dominant area and remaining tiles render in a sidebar/strip. Otherwise tiles\n * flow in an auto-sized grid.\n */\nexport function MeetingGrid({ tiles, pinned, className }: MeetingGridProps) {\n if (pinned) {\n return (\n <div className={cn(\"flex flex-col md:flex-row gap-2 h-full min-h-0\", className)}>\n <div className=\"flex-1 min-h-0\">{pinned}</div>\n {tiles.length > 0 && (\n <div className=\"flex md:flex-col gap-2 md:w-48 overflow-auto\">\n {tiles.map((t, i) => (\n <div key={i} className=\"min-w-40 md:min-w-0\">{t}</div>\n ))}\n </div>\n )}\n </div>\n );\n }\n\n const cols = tiles.length <= 1 ? \"grid-cols-1\"\n : tiles.length <= 4 ? \"grid-cols-2\"\n : tiles.length <= 9 ? \"grid-cols-3\"\n : \"grid-cols-4\";\n\n return (\n <div className={cn(\"grid gap-2 h-full\", cols, className)}>\n {tiles.map((t, i) => (\n <div key={i}>{t}</div>\n ))}\n </div>\n );\n}\n","import { Mic, MicOff, User, VideoOff } from \"lucide-react\";\nimport type { ReactNode } from \"react\";\nimport { cn } from \"../utils/cn\";\n\nexport interface ParticipantTileProps {\n name: string;\n avatarUrl?: string;\n muted?: boolean;\n speaking?: boolean;\n hasVideo?: boolean;\n videoSlot?: ReactNode;\n className?: string;\n /**\n * Fill the parent box (height + width) instead of keeping a 16:9 aspect\n * ratio. Use for a pinned/main tile inside a bounded container so it fits the\n * available space without deriving its height from its width (which would\n * overflow a wide surface). Grid thumbnails keep the default aspect ratio.\n */\n fill?: boolean;\n}\n\n/**\n * Provider-agnostic participant tile. Shows avatar + name when no video is\n * available; otherwise renders the `videoSlot` passed by the caller (typically\n * a <VideoSurface /> wired to a provider-specific stream renderer).\n */\nexport function ParticipantTile({\n name,\n avatarUrl,\n muted,\n speaking,\n hasVideo,\n videoSlot,\n className,\n fill,\n}: ParticipantTileProps) {\n return (\n <div\n className={cn(\n \"relative rounded-lg overflow-hidden bg-video-surface flex items-center justify-center\",\n fill ? \"h-full w-full\" : \"aspect-video\",\n speaking && \"ring-2 ring-speaking\",\n className,\n )}\n >\n {hasVideo && videoSlot ? (\n <div className=\"absolute inset-0\">{videoSlot}</div>\n ) : (\n <div className=\"flex flex-col items-center gap-2 text-gray-300\">\n {avatarUrl ? (\n <img src={avatarUrl} alt={name} className=\"w-16 h-16 rounded-full object-cover\" />\n ) : (\n <div className=\"w-16 h-16 rounded-full bg-video-surface-strong flex items-center justify-center\">\n {hasVideo ? <VideoOff className=\"w-8 h-8\" /> : <User className=\"w-8 h-8\" />}\n </div>\n )}\n </div>\n )}\n\n <div className=\"absolute bottom-2 left-2 flex items-center gap-1.5 px-2 py-1 rounded bg-video-overlay text-white text-xs\">\n {muted ? <MicOff className=\"w-3 h-3\" /> : <Mic className=\"w-3 h-3\" />}\n <span className=\"truncate max-w-35\">{name}</span>\n </div>\n </div>\n );\n}\n","import { useEffect, useRef } from \"react\";\nimport { cn } from \"../utils/cn\";\n\nexport interface VideoSurfaceProps {\n /**\n * Provider-specific mount callback. Receives the container element so\n * provider SDKs (Azure, Zoom, etc.) can attach their own video renderer.\n * Return an optional cleanup function.\n */\n attach: (el: HTMLDivElement) => void | (() => void);\n active?: boolean;\n mirrored?: boolean;\n className?: string;\n}\n\n/**\n * Provider-agnostic video tile surface. Owns the DOM slot; the caller wires\n * their SDK's renderer to it via `attach`.\n */\nexport function VideoSurface({ attach, active = true, mirrored = false, className }: VideoSurfaceProps) {\n const ref = useRef<HTMLDivElement>(null);\n\n useEffect(() => {\n if (!active || !ref.current) return;\n const cleanup = attach(ref.current);\n return () => {\n if (typeof cleanup === \"function\") cleanup();\n if (ref.current) ref.current.innerHTML = \"\";\n };\n }, [attach, active]);\n\n return (\n <div\n ref={ref}\n className={cn(\n \"w-full h-full bg-video-surface-strong overflow-hidden\",\n mirrored && \"[&>*]:scale-x-[-1]\",\n className,\n )}\n />\n );\n}\n","import React, { forwardRef } from 'react';\nimport { cn } from '../utils/cn';\n\nexport interface ButtonProps extends React.ButtonHTMLAttributes<HTMLButtonElement> {\n /**\n * The visual style variant of the button\n */\n variant?: 'primary' | 'secondary' | 'outline' | 'ghost' | 'destructive' | 'success' | 'warning' | 'danger-solid';\n\n /**\n * The size of the button\n */\n size?: 'xs' | 'sm' | 'md' | 'lg' | 'xl' | '2xl' | 'full';\n\n /**\n * Whether the button should take the full width of its container\n */\n fullWidth?: boolean;\n\n /**\n * Whether the button is in a loading state\n */\n loading?: boolean;\n\n /**\n * Icon to display before the button text\n */\n leftIcon?: React.ReactNode;\n\n /**\n * Icon to display after the button text\n */\n rightIcon?: React.ReactNode;\n\n /**\n * Whether the button should only display an icon (no text)\n */\n iconOnly?: boolean;\n\n /** `circle` is for a control that is only ever an icon: call answer/reject. */\n shape?: 'default' | 'circle';\n}\n\n/**\n * Variant styles — semantic tokens only, so dark mode needs no extra classes.\n * One primary button per view; everything else is secondary, ghost or a Link.\n */\nconst buttonVariants = {\n primary: 'bg-accent text-accent-fg hover:bg-accent-hover disabled:bg-surface-hover',\n secondary: 'bg-surface-sunk text-text-strong hover:bg-surface-hover disabled:bg-surface-hover',\n // No resting fill, so no disabled fill either — a greyed-out plate where\n // there was nothing reads as a different control, not as a disabled one.\n outline: 'border border-border text-text-strong hover:bg-surface-hover',\n ghost: 'text-text-muted hover:bg-surface-hover hover:text-text',\n destructive:\n 'border border-danger-border bg-danger-soft text-danger-fg hover:border-danger disabled:bg-surface-hover',\n // Solid status fills. Reserved for a control whose colour IS the answer —\n // an RSVP, answering or rejecting a call — not for ordinary emphasis.\n success: 'bg-success text-text-inverse hover:opacity-90 disabled:bg-surface-hover',\n warning: 'bg-warning text-text-inverse hover:opacity-90 disabled:bg-surface-hover',\n 'danger-solid': 'bg-danger text-text-inverse hover:opacity-90 disabled:bg-surface-hover',\n};\n\n/** Height comes from the shared control tokens so buttons line up with inputs. */\nconst buttonSizes = {\n xs: 'h-control-xs px-2 text-xs',\n sm: 'h-control-sm px-3 text-sm',\n md: 'h-control-md px-4 text-sm',\n lg: 'h-control-lg px-4 text-sm',\n xl: 'h-control-xl px-6 text-base',\n '2xl': 'h-control-2xl px-6 text-base',\n full: 'h-control-md px-4 text-sm',\n};\n\nconst iconOnlySizes = {\n xs: 'h-control-xs w-6',\n sm: 'h-control-sm w-7',\n md: 'h-control-md w-8',\n lg: 'h-control-lg w-9',\n xl: 'h-control-xl w-10',\n '2xl': 'h-control-2xl w-12',\n full: 'h-control-md w-8',\n};\n\n/**\n * Button component with theme integration and multiple variants\n *\n * @example\n * ```tsx\n * <Button variant=\"primary\" size=\"md\">Click me</Button>\n * <Button variant=\"outline\" leftIcon={<Icon name={Plus} />}>Add item</Button>\n * <Button iconOnly variant=\"ghost\" aria-label=\"Zoeken\">\n * <Icon name={Search} />\n * </Button>\n * ```\n */\nexport const Button = forwardRef<HTMLButtonElement, ButtonProps>(\n (\n {\n variant = 'primary',\n size = 'md',\n fullWidth = false,\n loading = false,\n leftIcon,\n rightIcon,\n iconOnly = false,\n shape = 'default',\n className,\n children,\n disabled,\n ...props\n },\n ref\n ) => {\n const isDisabled = disabled || loading;\n\n return (\n <button\n ref={ref}\n type=\"button\"\n className={cn(\n // font-medium, not semibold: in the design a button's label carries\n // the same weight as an emphasised nav item, and 600 at 12–13px\n // reads as a heavier control than the surrounding chrome.\n 'inline-flex shrink-0 items-center justify-center gap-2 cursor-pointer font-medium',\n shape === 'circle' ? 'rounded-full' : 'rounded-md',\n 'transition-colors duration-fast ease-out',\n 'focus-visible:outline-none focus-visible:focus-ring',\n 'disabled:cursor-not-allowed disabled:border-border-subtle',\n 'disabled:text-text-disabled',\n\n buttonVariants[variant],\n iconOnly ? iconOnlySizes[size] : buttonSizes[size],\n\n (fullWidth || size === 'full') && 'w-full',\n loading && 'cursor-wait',\n\n className\n )}\n disabled={isDisabled}\n aria-busy={loading || undefined}\n {...props}\n >\n {loading && (\n <span\n aria-hidden\n className=\"size-icon-md shrink-0 animate-spin rounded-full border-2 border-current border-t-transparent\"\n />\n )}\n\n {!loading && leftIcon && <span className=\"flex items-center justify-center shrink-0\">{leftIcon}</span>}\n\n {!iconOnly && children}\n\n {!loading && rightIcon && <span className=\"flex items-center justify-center shrink-0\">{rightIcon}</span>}\n\n {iconOnly && !loading && !leftIcon && !rightIcon && children}\n </button>\n );\n }\n);\n\nButton.displayName = 'Button';\n","import React from 'react';\nimport { cn } from '../utils/cn';\n\nexport interface ButtonGroupProps {\n /** Child buttons to group */\n children: React.ReactNode;\n /** Size of the button group */\n size?: 'xs' | 'sm' | 'md' | 'lg' | 'xl';\n /** Orientation of the button group */\n orientation?: 'horizontal' | 'vertical';\n /** Whether buttons should be attached (no gap) */\n attached?: boolean;\n /** Additional CSS classes */\n className?: string;\n}\n\n/**\n * ButtonGroup component for grouping related buttons\n */\nexport const ButtonGroup: React.FC<ButtonGroupProps> = ({\n children,\n size = 'md',\n orientation = 'horizontal',\n attached = true,\n className,\n}) => {\n const baseClasses = cn(\n 'inline-flex',\n {\n // Orientation\n 'flex-row': orientation === 'horizontal',\n 'flex-col': orientation === 'vertical',\n \n // Attached styling\n '[&>*:not(:first-child):not(:last-child)]:rounded-none': attached,\n '[&>*:first-child]:rounded-r-none': attached && orientation === 'horizontal',\n '[&>*:last-child]:rounded-l-none': attached && orientation === 'horizontal',\n '[&>*:first-child]:rounded-b-none': attached && orientation === 'vertical',\n '[&>*:last-child]:rounded-t-none': attached && orientation === 'vertical',\n \n // Borders for attached buttons\n '[&>*:not(:first-child)]:-ml-px': attached && orientation === 'horizontal',\n '[&>*:not(:first-child)]:-mt-px': attached && orientation === 'vertical',\n \n // Spacing for non-attached buttons\n 'gap-1': !attached && size === 'xs',\n 'gap-2': !attached && (size === 'sm' || size === 'md'),\n 'gap-3': !attached && (size === 'lg' || size === 'xl'),\n },\n className\n );\n\n return (\n <div className={baseClasses} role=\"group\">\n {children}\n </div>\n );\n}; ","import * as LucideIcons from 'lucide-react';\nimport React from 'react';\nimport { cn } from '../utils/cn';\n\n/**\n * Lucide icon by name, for icons that arrive as data rather than as an import —\n * a provider declaring `icon: \"MessageCircle\"` in its description, a menu entry\n * from a manifest. Accepts kebab-case, snake_case, spaced or PascalCase.\n *\n * Returns `undefined` for an unknown name so the caller can fall back; an app\n * naming an icon that does not exist should not blank out the surface.\n */\nexport function resolveLucideIcon(name: string | undefined): React.ComponentType<any> | undefined {\n if (!name) return undefined;\n const pascal = name\n .split(/[-_ ]/)\n .filter(Boolean)\n .map((part) => part.charAt(0).toUpperCase() + part.slice(1))\n .join('');\n const found = (LucideIcons as unknown as Record<string, unknown>)[pascal];\n return typeof found === 'function' || (typeof found === 'object' && found !== null)\n ? (found as React.ComponentType<any>)\n : undefined;\n}\n\nexport interface IconProps {\n /** Icon component from lucide-react or custom icon */\n icon: React.ComponentType<any>;\n /** Icon size */\n size?: 'xs' | 'sm' | 'md' | 'lg' | 'xl' | number;\n /** Icon color */\n color?: 'primary' | 'secondary' | 'accent' | 'success' | 'warning' | 'error' | 'info' | 'neutral' | 'current';\n /** Whether the icon should be clickable */\n clickable?: boolean;\n /** Click handler */\n onClick?: () => void;\n /** Additional CSS classes */\n className?: string;\n /** Accessibility label */\n 'aria-label'?: string;\n}\n\n/**\n * Icon — the only way icons enter the product. Always a lucide-react component;\n * never a unicode glyph, an emoji or an inline <svg> in feature code.\n *\n * Sizes follow the icon tokens: xs 12 · sm 14 (default in controls) · md 16 ·\n * lg 20 · xl 24.\n */\nconst colorMap: Record<NonNullable<IconProps['color']>, string> = {\n primary: 'text-text',\n secondary: 'text-text-muted',\n accent: 'text-accent',\n success: 'text-success-fg',\n warning: 'text-warning-fg',\n error: 'text-danger-fg',\n info: 'text-info-fg',\n neutral: 'text-text-subtle',\n current: 'text-current',\n};\n\nexport const Icon: React.FC<IconProps> = ({\n icon: IconComponent,\n size = 'md',\n color = 'current',\n clickable = false,\n onClick,\n className,\n 'aria-label': ariaLabel,\n ...props\n}) => {\n const sizeValue = typeof size === 'number' ? size : getSizeValue(size);\n\n const iconClasses = cn(\n 'inline-block shrink-0',\n colorMap[color],\n clickable && [\n 'cursor-pointer rounded-sm transition-opacity duration-fast ease-out hover:opacity-80',\n 'focus-visible:outline-none focus-visible:focus-ring',\n ],\n className\n );\n\n const iconProps = {\n size: sizeValue,\n strokeWidth: 2,\n className: iconClasses,\n onClick: clickable ? onClick : undefined,\n 'aria-label': ariaLabel,\n 'aria-hidden': ariaLabel ? undefined : true,\n role: clickable ? 'button' : undefined,\n tabIndex: clickable ? 0 : undefined,\n onKeyDown: clickable\n ? (e: React.KeyboardEvent) => {\n if (e.key === 'Enter' || e.key === ' ') {\n e.preventDefault();\n onClick?.();\n }\n }\n : undefined,\n ...props,\n };\n\n return <IconComponent {...iconProps} />;\n};\n\nfunction getSizeValue(size: 'xs' | 'sm' | 'md' | 'lg' | 'xl'): number {\n const sizeMap = {\n xs: 12,\n sm: 14,\n md: 16,\n lg: 20,\n xl: 24,\n };\n\n return sizeMap[size];\n}\n","import React, { useEffect, useRef, useState } from \"react\";\nimport { cn } from \"../utils/cn\";\nimport { useAnchoredPosition } from \"../utils/useAnchoredPosition\";\n\nexport interface PopoverProps {\n /** Element that toggles the popover */\n trigger: React.ReactNode;\n /**\n * Panel content. Pass a function to receive a `close` callback so rows can\n * dismiss the popover after acting.\n */\n children: React.ReactNode | ((close: () => void) => React.ReactNode);\n /** Panel placement relative to the trigger. Flips when there is no room. */\n placement?: \"bottom-start\" | \"bottom-end\" | \"top-start\" | \"top-end\";\n /** Additional CSS classes for the panel */\n className?: string;\n /**\n * Layout classes for the wrapper around the trigger. Needed when the trigger\n * has to fill a positioned box — a calendar event in a week grid, say —\n * because the wrapper is `inline-flex` by default.\n */\n rootClassName?: string;\n /** Layout classes for the trigger button itself. */\n triggerClassName?: string;\n /** Whether the trigger is disabled */\n disabled?: boolean;\n /**\n * Accessible name for the trigger button. Needed when the trigger is\n * icon-only, since the panel content is not announced by the trigger.\n */\n triggerLabel?: string;\n}\n\n/**\n * Generic popover with click-outside / Escape dismissal. The panel is\n * `position: fixed` (computed from the trigger) so it escapes any\n * overflow-hidden or rounded-card ancestor instead of being clipped.\n */\nexport const Popover: React.FC<PopoverProps> = ({\n trigger,\n children,\n placement = \"bottom-start\",\n className,\n rootClassName,\n triggerClassName,\n disabled = false,\n triggerLabel,\n}) => {\n const [isOpen, setIsOpen] = useState(false);\n const rootRef = useRef<HTMLDivElement>(null);\n const triggerRef = useRef<HTMLButtonElement>(null);\n // Shared with Select, DatePicker and Dropdown: flips up when the trigger sits\n // near the bottom, caps the height to the space available, and re-measures on\n // scroll so the panel keeps tracking its trigger.\n const panelStyle = useAnchoredPosition(isOpen, triggerRef, { placement });\n\n useEffect(() => {\n if (!isOpen) return;\n const onDown = (event: MouseEvent) => {\n if (rootRef.current && !rootRef.current.contains(event.target as Node)) {\n setIsOpen(false);\n }\n };\n const onEsc = (event: KeyboardEvent) => {\n if (event.key === \"Escape\") setIsOpen(false);\n };\n document.addEventListener(\"mousedown\", onDown);\n document.addEventListener(\"keydown\", onEsc);\n return () => {\n document.removeEventListener(\"mousedown\", onDown);\n document.removeEventListener(\"keydown\", onEsc);\n };\n }, [isOpen]);\n\n const handleToggle = (event: React.MouseEvent<HTMLButtonElement>) => {\n event.stopPropagation();\n if (disabled) return;\n setIsOpen((open) => !open);\n };\n\n const close = () => setIsOpen(false);\n\n return (\n <div ref={rootRef} className={cn(\"relative inline-flex\", rootClassName)}>\n <button\n ref={triggerRef}\n type=\"button\"\n onClick={handleToggle}\n disabled={disabled}\n aria-label={triggerLabel}\n aria-expanded={isOpen}\n className={cn(\n \"inline-flex items-center\",\n disabled && \"cursor-not-allowed opacity-50\",\n triggerClassName,\n )}\n >\n {trigger}\n </button>\n\n {isOpen && (\n <div\n className={cn(\n // overflow-y-auto pairs with the hook's max-height: without it a\n // panel taller than the space available is simply cut off.\n \"fixed z-overlay overflow-y-auto rounded-lg border border-border bg-surface shadow-overlay\",\n className,\n )}\n style={panelStyle}\n >\n {typeof children === \"function\" ? children(close) : children}\n </div>\n )}\n </div>\n );\n};\n","import { ChevronDown, X } from \"lucide-react\";\nimport React from \"react\";\nimport { Icon } from \"../content/Icon\";\nimport { Popover } from \"../overlays/Popover\";\nimport { cn } from \"../utils/cn\";\n\nexport interface FilterChipProps {\n /** Chip text (e.g. \"Status\", or \"Status: Open\" when a value is set). */\n label: React.ReactNode;\n /** Leading icon, before the label. */\n icon?: React.ReactNode;\n /**\n * Meaning carried by the chip's own value — a priority, a state. Applies to\n * the resting chip; `active` still wins, because \"you picked this\" outranks\n * \"this is urgent\".\n */\n tone?: \"none\" | \"default\" | \"muted\" | \"outline\" | \"warning\" | \"danger\";\n /**\n * `rect` is the filter-bar shape — the same 9px corner as a button, so a\n * chip and a button in one toolbar line up. `pill` is for a chip that reads\n * as a tag rather than a control.\n */\n shape?: \"pill\" | \"rect\";\n /** `md` is the default control height; `sm` for a dense toolbar. */\n size?: \"sm\" | \"md\";\n /** Selected/active — renders the filled dark treatment. */\n active?: boolean;\n /** Show a trailing caret (opens a menu the consumer wires with Dropdown/Popover). */\n caret?: boolean;\n /**\n * Menu panel for a chip that opens its own popover. Receives a `close`\n * callback so a row can dismiss the panel after picking. Without it the chip\n * is purely presentational and `onClick` is yours to wire.\n */\n menu?: (close: () => void) => React.ReactNode;\n /** Panel classes, when `menu` is set. */\n menuClassName?: string;\n /** Open a value clear affordance (✕) — only shown when `active`. */\n onClear?: () => void;\n /** Accessible name for the clear affordance. */\n clearLabel?: string;\n onClick?: () => void;\n /** Native tooltip, for a chip whose label is truncated or abbreviated. */\n title?: string;\n className?: string;\n}\n\n/**\n * Resting fills. A filter bar on the white card uses sunk plates — an outlined\n * row of chips reads as a row of empty inputs at this size. `outline` is the\n * exception, for a bar that already contains a sunk plate (the table toolbar,\n * where the search field is the sunk one): there a second sunk fill beside it\n * makes the two read as one smeared control.\n */\nconst tones: Record<NonNullable<FilterChipProps[\"tone\"]>, string> = {\n none: \"hover:bg-surface-sunk hover:text-text\",\n default: \"bg-surface-sunk text-text-muted hover:text-text\",\n muted: \"bg-surface-sunk text-text-subtle hover:text-text\",\n outline:\n \"text-text-muted ring-1 ring-inset ring-border-strong hover:bg-surface-hover hover:text-text\",\n warning: \"bg-warning-soft text-warning-fg\",\n danger: \"bg-danger-soft text-danger-fg\",\n};\n\ntype ChipShape = NonNullable<FilterChipProps[\"shape\"]>;\n\nconst chipShell = (opts: {\n active?: boolean;\n tone?: NonNullable<FilterChipProps[\"tone\"]>;\n shape?: ChipShape;\n size?: NonNullable<FilterChipProps[\"size\"]>;\n className?: string;\n}) =>\n cn(\n // A button's default cursor is an arrow, so it has to be asked for.\n \"inline-flex cursor-pointer select-none items-center text-sm font-medium\",\n opts.size === \"sm\" ? \"h-control-sm\" : \"h-control-md\",\n \"transition-colors duration-fast ease-out\",\n opts.shape === \"pill\" ? \"rounded-full\" : \"rounded-md\",\n // Picking a value outranks whatever the value happens to mean.\n opts.active ? \"bg-info-soft text-info-fg\" : tones[opts.tone ?? \"default\"],\n opts.className,\n );\n\nconst chipBody = (opts: { shape?: ChipShape; withClear?: boolean }) =>\n cn(\n \"inline-flex items-center gap-1.5 pl-3\",\n opts.shape === \"pill\" ? \"rounded-full\" : \"rounded-md\",\n opts.withClear ? \"pr-1.5\" : \"pr-3\",\n \"focus-visible:outline-none focus-visible:focus-ring\",\n );\n\n\n/**\n * Filter chip — the inbox filter bar, the table toolbar, and the thread\n * priority/assign/inbox/tags menus. Presentational by default (the consumer\n * wires the menu with `Dropdown`/`Popover` and `onClick`); pass `menu` and the\n * chip opens its own popover instead, which is the only way to get a clear\n * button on a menu chip — a `<FilterChip>` used as someone else's trigger\n * would nest a button inside a button.\n *\n * @example\n * ```tsx\n * <FilterChip label={status ? `Status: ${status}` : \"Status\"} caret\n * active={!!status} onClear={() => setStatus(null)}\n * menu={(close) => <StatusList onPick={(s) => { setStatus(s); close(); }} />} />\n * ```\n */\nexport function FilterChip({\n label,\n icon,\n tone = \"default\",\n shape = \"rect\",\n size = \"md\",\n active = false,\n caret = false,\n menu,\n menuClassName,\n onClear,\n clearLabel = \"Filter wissen\",\n onClick,\n title,\n className,\n}: FilterChipProps) {\n const showClear = active && Boolean(onClear);\n\n // The chip and its clear affordance are two separate controls, so the shell is\n // a plain span: a <button> may not contain another <button>. Without a clear,\n // there is only one control and the shell collapses onto it.\n const radius = shape === \"pill\" ? \"rounded-full\" : \"rounded-md\";\n\n const shell = chipShell({ active, tone, shape, size, className });\n\n const body = (\n <>\n {icon}\n {label}\n {caret && <Icon icon={ChevronDown} size=\"xs\" />}\n </>\n );\n\n const bodyClasses = chipBody({ shape, withClear: showClear });\n\n const clearButton = showClear && (\n <button\n type=\"button\"\n aria-label={clearLabel}\n onClick={onClear}\n className={cn(\"inline-flex h-full items-center pr-3 focus-visible:outline-none focus-visible:focus-ring\", radius)}\n >\n <Icon icon={X} size=\"xs\" />\n </button>\n );\n\n if (menu) {\n return (\n <span className={shell} title={title}>\n <Popover\n trigger={body}\n // Both heights are needed: the shell has the definite height, so the\n // trigger only fills the plate if the wrapper passes it down.\n rootClassName=\"h-full\"\n triggerClassName={cn(bodyClasses, \"h-full\")}\n className={cn(\"min-w-menu p-1.5\", menuClassName)}\n >\n {menu}\n </Popover>\n {clearButton}\n </span>\n );\n }\n\n if (!showClear) {\n return (\n <button type=\"button\" title={title} onClick={onClick} className={cn(shell, bodyClasses)}>\n {body}\n </button>\n );\n }\n\n return (\n <span className={shell} title={title}>\n <button type=\"button\" onClick={onClick} className={bodyClasses}>\n {body}\n </button>\n {clearButton}\n </span>\n );\n}\n","import React from 'react';\nimport { ExternalLink } from 'lucide-react';\nimport { cn } from '../utils/cn';\n\nexport interface LinkProps extends React.AnchorHTMLAttributes<HTMLAnchorElement> {\n /** Link variant */\n variant?: 'default' | 'subtle' | 'underline' | 'button';\n /** Link size */\n size?: 'xs' | 'sm' | 'md' | 'lg' | 'xl';\n /** Color theme */\n color?: 'primary' | 'secondary' | 'accent' | 'success' | 'warning' | 'error' | 'info' | 'neutral';\n /** Whether the link is disabled */\n disabled?: boolean;\n /** Whether to show external link icon */\n external?: boolean;\n /** Additional CSS classes */\n className?: string;\n /** Child content */\n children: React.ReactNode;\n}\n\n/** Same steps as Text: xs 11 · sm 12 · md 13 · lg 14 · xl 16. */\nconst sizeMap: Record<NonNullable<LinkProps['size']>, string> = {\n xs: 'text-xs',\n sm: 'text-sm',\n md: 'text-base',\n lg: 'text-md',\n xl: 'text-lg',\n};\n\nconst colorMap: Record<NonNullable<LinkProps['color']>, string> = {\n primary: 'text-text hover:text-info-fg hover:underline',\n info: 'text-info-fg hover:underline',\n secondary: 'text-text-muted hover:text-text',\n neutral: 'text-text-muted hover:text-text',\n accent: 'text-accent hover:underline',\n success: 'text-success-fg hover:underline',\n warning: 'text-warning-fg hover:underline',\n error: 'text-danger-fg hover:underline',\n};\n\n/** `variant=\"button\"` uses the soft surface of the matching status token. */\nconst buttonBackgroundMap: Record<NonNullable<LinkProps['color']>, string> = {\n primary: 'bg-accent-soft',\n accent: 'bg-accent-soft',\n secondary: 'bg-surface-hover',\n neutral: 'bg-surface-hover',\n success: 'bg-success-soft',\n warning: 'bg-warning-soft',\n error: 'bg-danger-soft',\n info: 'bg-info-soft',\n};\n\n/**\n * Link component with theme integration and accessibility features.\n * Use for navigation; use Button for actions.\n */\nexport const Link: React.FC<LinkProps> = ({\n variant = 'default',\n size = 'md',\n color = 'primary',\n disabled = false,\n external = false,\n className,\n children,\n href,\n target,\n rel,\n ...props\n}) => {\n const isExternal =\n external || (href && (href.startsWith('http') || href.startsWith('mailto:')));\n\n const baseClasses = cn(\n 'inline-flex items-center gap-1 underline-offset-2',\n 'transition-colors duration-fast ease-out',\n 'focus-visible:outline-none focus-visible:focus-ring',\n\n sizeMap[size],\n !disabled && colorMap[color],\n\n variant === 'subtle' && 'no-underline opacity-70 hover:opacity-100',\n variant === 'underline' && 'underline decoration-1 hover:decoration-2',\n variant === 'button' && [\n 'h-control-md rounded-md px-3 font-semibold no-underline hover:no-underline',\n buttonBackgroundMap[color],\n ],\n\n disabled && 'pointer-events-none cursor-not-allowed text-text-disabled opacity-50',\n\n className\n );\n\n const linkProps = {\n ...props,\n href: disabled ? undefined : href,\n target: isExternal ? '_blank' : target,\n rel: isExternal ? 'noopener noreferrer' : rel,\n 'aria-disabled': disabled || undefined,\n };\n\n return (\n <a className={baseClasses} {...linkProps}>\n {children}\n {isExternal && <ExternalLink className=\"size-icon-sm shrink-0\" aria-hidden />}\n </a>\n );\n};\n","import React from \"react\";\nimport { cn } from \"../utils/cn\";\n\nexport interface SegmentedOption<T extends string> {\n value: T;\n label: React.ReactNode;\n /**\n * Accessible name and tooltip, for a segment whose label is an icon. Without\n * it an icon-only segment announces as an empty tab.\n */\n title?: string;\n}\n\nexport interface SegmentedToggleProps<T extends string> {\n options: SegmentedOption<T>[];\n value: T;\n onChange: (value: T) => void;\n /** Control height. */\n size?: \"sm\" | \"md\";\n /**\n * Track fill. `sunk` reads against the white card; use `track` when the\n * toggle itself sits on a sunk plane, where `sunk` on `sunk` is invisible.\n */\n tone?: \"sunk\" | \"track\";\n /** Fill the container and split it evenly — a toggle that heads a column. */\n fullWidth?: boolean;\n className?: string;\n /** Accessible group label. */\n \"aria-label\"?: string;\n}\n\n/** Track height stays one step below the equivalent Button so it nests in toolbars. */\nconst sizes = {\n sm: \"h-control-sm px-3 text-sm\",\n md: \"h-control-md px-3 text-sm\",\n};\n\n/**\n * Segmented toggle (focus \"Feed / Eén tegelijk\", tasks \"Mijn / Mijn teams\").\n * Track = surface-sunk, active segment = a raised white plate — the same\n * \"lifted off the plane behind it\" language as the active nav item.\n *\n * @example\n * ```tsx\n * <SegmentedToggle\n * value={layout}\n * onChange={setLayout}\n * options={[{ value: \"feed\", label: \"Feed\" }, { value: \"one\", label: \"Eén tegelijk\" }]}\n * />\n * ```\n */\nexport function SegmentedToggle<T extends string>({\n options,\n value,\n onChange,\n size = \"sm\",\n tone = \"sunk\",\n fullWidth = false,\n className,\n \"aria-label\": ariaLabel,\n}: SegmentedToggleProps<T>) {\n return (\n <div\n role=\"tablist\"\n aria-label={ariaLabel}\n className={cn(\n \"gap-0.5 rounded-md p-0.5\",\n tone === \"track\" ? \"bg-surface-track\" : \"bg-surface-sunk\",\n fullWidth ? \"flex w-full\" : \"inline-flex\",\n className,\n )}\n >\n {options.map((opt) => {\n const active = opt.value === value;\n return (\n <button\n key={opt.value}\n role=\"tab\"\n aria-selected={active}\n aria-label={opt.title}\n title={opt.title}\n type=\"button\"\n onClick={() => onChange(opt.value)}\n className={cn(\n \"inline-flex cursor-pointer items-center justify-center gap-1.5 rounded-sm\",\n \"transition-colors duration-fast ease-out\",\n \"focus-visible:outline-none focus-visible:focus-ring\",\n fullWidth && \"min-w-0 flex-1\",\n sizes[size],\n active ? \"bg-surface text-text font-medium shadow-sm\" : \"text-text-muted hover:text-text\",\n )}\n >\n {opt.label}\n </button>\n );\n })}\n </div>\n );\n}\n","import { ChevronDown } from \"lucide-react\";\nimport React from \"react\";\nimport { Popover } from \"../overlays/Popover\";\nimport { cn } from \"../utils/cn\";\nimport { Button } from \"./Button\";\n\nexport interface SplitButtonOption {\n id: string;\n label: string;\n onClick: () => void;\n variant?: \"default\" | \"destructive\";\n /** Optioneel icoon vóór het label in het menu. */\n icon?: React.ReactNode;\n}\n\nexport interface SplitButtonProps {\n label: string;\n onClick: () => void;\n variant?: \"primary\" | \"secondary\" | \"outline\";\n size?: \"sm\" | \"md\";\n icon?: React.ReactNode;\n options: SplitButtonOption[];\n disabled?: boolean;\n /** Spinner in de primaire helft; blokkeert beide helften. */\n loading?: boolean;\n /**\n * Waar het optie-menu opent. Gebruik een `top-*` placement wanneer de knop\n * onderaan zijn container staat (bv. een sticky verzendbalk).\n */\n menuPlacement?: \"bottom-end\" | \"bottom-start\" | \"top-end\" | \"top-start\";\n /** Accessible naam voor de chevron-knop. */\n menuLabel?: string;\n}\n\n/** Zelfde varianttokens als Button, zodat beide helften één knop lijken. */\nconst variantStyles = {\n primary: \"bg-accent text-accent-fg hover:bg-accent-hover\",\n secondary: \"border border-border bg-surface text-text hover:bg-surface-hover\",\n outline: \"border border-accent-border text-accent hover:bg-accent-soft\",\n};\n\nconst chevronSizes = {\n sm: \"h-control-sm w-7\",\n md: \"h-control-md w-8\",\n};\n\n/**\n * Knop met een primaire actie plus een chevron-menu voor varianten daarvan.\n * De primaire helft is een gewone `Button` (zelfde varianten/loading-gedrag);\n * het menu loopt via `Popover`, dus het is `position: fixed` en wordt niet\n * geklipt door een scrollende of overflow-hidden voorouder.\n *\n * Zonder opties rendert dit precies een `Button` — geen chevron.\n */\nexport function SplitButton({\n label,\n onClick,\n variant = \"primary\",\n size = \"md\",\n icon,\n options,\n disabled = false,\n loading = false,\n menuPlacement = \"bottom-end\",\n menuLabel = \"More options\",\n}: SplitButtonProps) {\n const isDisabled = disabled || loading;\n const hasMenu = options.length > 0;\n\n return (\n // De scheiding tussen beide helften is een kier in de vulling, niet een\n // lijn: bij een ink-gevulde knop leest 2px als een spleet. 1px is genoeg\n // om te zien dat het twee doelen zijn. De omrande varianten hebben hun\n // eigen randen al en houden de helften tegen elkaar.\n <div className={cn(\"inline-flex items-center\", variant === \"primary\" && \"gap-px\")}>\n <Button\n variant={variant}\n size={size}\n onClick={onClick}\n disabled={disabled}\n loading={loading}\n leftIcon={icon}\n className={cn(hasMenu && \"rounded-r-none\")}\n >\n {label}\n </Button>\n {hasMenu && (\n <Popover\n placement={menuPlacement}\n disabled={isDisabled}\n triggerLabel={menuLabel}\n className=\"min-w-menu py-1\"\n trigger={\n <span\n aria-hidden=\"true\"\n className={cn(\n \"inline-flex items-center justify-center rounded-md rounded-l-none\",\n \"transition-colors duration-fast ease-out\",\n variantStyles[variant],\n chevronSizes[size],\n isDisabled && \"cursor-not-allowed opacity-50\",\n )}\n >\n <ChevronDown className=\"size-icon-md\" />\n </span>\n }\n >\n {(close) => (\n <>\n {options.map((option) => (\n <button\n key={option.id}\n type=\"button\"\n onClick={() => {\n option.onClick();\n close();\n }}\n className={cn(\n \"flex w-full items-center gap-2 px-3 py-1.5 text-left text-sm\",\n \"transition-colors duration-fast ease-out\",\n \"focus-visible:outline-none focus-visible:focus-ring\",\n option.variant === \"destructive\"\n ? \"text-danger-fg hover:bg-danger-soft\"\n : \"text-text hover:bg-surface-hover\",\n )}\n >\n {option.icon && (\n <span className=\"shrink-0\">{option.icon}</span>\n )}\n {option.label}\n </button>\n ))}\n </>\n )}\n </Popover>\n )}\n </div>\n );\n}\n","import React, { forwardRef } from 'react';\nimport { cn } from '../utils/cn';\n\nexport interface CheckboxProps extends Omit<React.InputHTMLAttributes<HTMLInputElement>, 'size'> {\n /**\n * The label for the checkbox\n */\n label?: string;\n\n /**\n * Helper text to display below the checkbox\n */\n helperText?: string;\n\n /**\n * Error message to display when the checkbox is invalid\n */\n error?: string;\n\n /**\n * The size of the checkbox\n */\n size?: 'sm' | 'md' | 'lg' | 'full';\n\n /**\n * Whether the checkbox is in an indeterminate state\n */\n indeterminate?: boolean;\n\n /**\n * Additional class name for the container\n */\n containerClassName?: string;\n\n /**\n * Additional class name for the label\n */\n labelClassName?: string;\n}\n\n/** The box grows with the field size, so a checkbox row reads as the same\n * weight as the inputs beside it instead of a small mark floating next to them. */\nconst checkboxSizes = {\n sm: 'size-checkbox-sm',\n md: 'size-checkbox',\n lg: 'size-checkbox-lg',\n full: 'size-checkbox',\n};\n\n/** Row height matches the control tokens so a checkbox lines up in a form. */\nconst rowSizes = {\n sm: 'min-h-control-sm',\n md: 'min-h-control-md',\n lg: 'min-h-control-lg',\n full: 'min-h-control-md',\n};\n\n/**\n * `full` means full width, not large: it mirrors `md` here the same way\n * `checkboxSizes` and `rowSizes` do, and the same way every other control in\n * the kit keeps `text-base` at `full`. It used to read `text-md`, which made\n * the label a step bigger than every field beside it — every Form passes\n * `size=\"full\"`, so that hit each checkbox in every form in the product.\n */\nconst labelSizes = {\n sm: 'text-sm',\n md: 'text-base',\n lg: 'text-md',\n full: 'text-base',\n};\n\n/**\n * Checkbox component with theme integration.\n *\n * Uses the native input with `accent-color`, so the checked fill is the accent\n * token and dark mode needs no extra classes.\n *\n * @example\n * ```tsx\n * <Checkbox label=\"Voorwaarden accepteren\" />\n * <Checkbox label=\"Alles selecteren\" indeterminate />\n * ```\n */\nexport const Checkbox = forwardRef<HTMLInputElement, CheckboxProps>(\n (\n {\n label,\n helperText,\n error,\n size = 'md',\n indeterminate = false,\n containerClassName,\n labelClassName,\n className,\n id,\n ...props\n },\n ref\n ) => {\n const reactId = React.useId();\n const checkboxId = id || `checkbox-${reactId}`;\n const hasError = Boolean(error);\n const innerRef = React.useRef<HTMLInputElement | null>(null);\n\n // Keep the forwarded ref and the internal one in sync so `indeterminate`\n // works whether or not the consumer passes a ref.\n const setRefs = React.useCallback(\n (node: HTMLInputElement | null) => {\n innerRef.current = node;\n if (typeof ref === 'function') ref(node);\n else if (ref && typeof ref === 'object') {\n (ref as React.MutableRefObject<HTMLInputElement | null>).current = node;\n }\n },\n [ref]\n );\n\n React.useEffect(() => {\n if (innerRef.current) innerRef.current.indeterminate = indeterminate;\n }, [indeterminate]);\n\n return (\n <div className={cn('flex flex-col', containerClassName)}>\n <div className={cn('flex items-center gap-3', rowSizes[size])}>\n <input\n ref={setRefs}\n id={checkboxId}\n type=\"checkbox\"\n aria-invalid={hasError || undefined}\n className={cn(\n // radius-xs (5px): its own step on the scale. At 16px the 9px\n // button radius reads as a circle and the 7px chip radius still\n // rounds the corners away — a checkbox has to stay a square you\n // can aim at, with the corner just knocked off.\n 'shrink-0 rounded-xs border accent-accent',\n 'transition-colors duration-fast ease-out',\n 'focus-visible:outline-none focus-visible:focus-ring',\n 'disabled:cursor-not-allowed disabled:bg-surface-hover',\n\n checkboxSizes[size],\n hasError ? 'border-danger-border' : 'border-border-strong',\n\n className\n )}\n {...props}\n />\n\n {label && (\n <div className=\"flex-1\">\n <label\n htmlFor={checkboxId}\n className={cn(\n 'cursor-pointer',\n hasError ? 'text-danger-fg' : 'text-text',\n labelSizes[size],\n labelClassName\n )}\n >\n {label}\n </label>\n\n {helperText && !error && (\n <p className=\"mt-0.5 text-xs text-text-subtle\">{helperText}</p>\n )}\n </div>\n )}\n </div>\n\n {error && <p className=\"mt-1 text-xs text-danger-fg\">{error}</p>}\n </div>\n );\n }\n);\n\nCheckbox.displayName = 'Checkbox';\n","import React from 'react';\nimport { cn } from '../utils/cn';\n\nexport interface TextProps {\n /** Text variant */\n variant?: 'body' | 'caption' | 'label' | 'code';\n /** Text size */\n size?: 'xs' | 'sm' | 'md' | 'lg' | 'xl';\n /** Font weight */\n weight?: 'light' | 'normal' | 'medium' | 'semibold' | 'bold';\n /** Text color */\n color?: 'primary' | 'secondary' | 'accent' | 'success' | 'warning' | 'error' | 'info' | 'neutral' | 'current' | 'muted';\n /** Text alignment */\n align?: 'left' | 'center' | 'right' | 'justify';\n /** Whether to truncate text with ellipsis */\n truncate?: boolean;\n /** Whether text should be italic */\n italic?: boolean;\n /** Whether text should be underlined */\n underline?: boolean;\n /** Line height */\n lineHeight?: 'tight' | 'normal' | 'relaxed';\n /** HTML element to render */\n as?: 'p' | 'span' | 'div' | 'code' | 'pre';\n /** Additional CSS classes */\n className?: string;\n /** Child content */\n children: React.ReactNode;\n}\n\n/**\n * Text — every copy string in the product goes through this component.\n *\n * Size maps onto the token type scale (tokens.css):\n * xs 11 · sm 12 · md 13 (body) · lg 14 (long-form) · xl 16\n * Anything above 16px is a Heading, not Text.\n */\nconst sizeMap: Record<NonNullable<TextProps['size']>, string> = {\n xs: 'text-xs',\n sm: 'text-sm',\n md: 'text-base',\n lg: 'text-md',\n xl: 'text-lg',\n};\n\nconst weightMap: Record<NonNullable<TextProps['weight']>, string> = {\n light: 'font-normal',\n normal: 'font-normal',\n medium: 'font-medium',\n semibold: 'font-semibold',\n bold: 'font-bold',\n};\n\n/** Semantic colour tokens — these flip in dark mode, so no `dark:` variants. */\nconst colorMap: Record<NonNullable<TextProps['color']>, string> = {\n primary: 'text-text',\n secondary: 'text-text-muted',\n accent: 'text-accent',\n success: 'text-success-fg',\n warning: 'text-warning-fg',\n error: 'text-danger-fg',\n info: 'text-info-fg',\n neutral: 'text-text',\n current: 'text-current',\n muted: 'text-text-subtle',\n};\n\nconst alignMap: Record<NonNullable<TextProps['align']>, string> = {\n left: 'text-left',\n center: 'text-center',\n right: 'text-right',\n justify: 'text-justify',\n};\n\nconst lineHeightMap: Record<NonNullable<TextProps['lineHeight']>, string> = {\n tight: 'leading-tight',\n normal: 'leading-normal',\n relaxed: 'leading-relaxed',\n};\n\nexport const Text: React.FC<TextProps> = ({\n variant = 'body',\n size = 'md',\n weight = 'normal',\n color = 'current',\n align = 'left',\n truncate = false,\n italic = false,\n underline = false,\n lineHeight = 'normal',\n as,\n className,\n children,\n ...props\n}) => {\n const Tag = (as || getDefaultElement(variant)) as keyof React.JSX.IntrinsicElements;\n\n const isCaption = variant === 'caption';\n const isLabel = variant === 'label';\n const isCode = variant === 'code';\n\n const textClasses = cn(\n 'font-sans',\n\n // Variant — caption and label pin their own size/weight\n isCaption && 'text-xs text-text-subtle',\n isLabel && 'text-xs font-semibold uppercase tracking-label text-text-subtle',\n isCode && 'font-mono text-sm rounded-sm bg-surface-hover px-1 py-0.5',\n\n // Size — only where the variant does not pin it\n !isCaption && !isLabel && !isCode && sizeMap[size],\n\n // Weight — label owns its weight\n !isLabel && weightMap[weight],\n\n colorMap[color],\n alignMap[align],\n\n // Line height only overrides the body variant\n variant === 'body' && lineHeightMap[lineHeight],\n\n italic && 'italic',\n underline && 'underline',\n truncate && 'truncate',\n\n className\n );\n\n return (\n <Tag className={textClasses} {...props}>\n {children}\n </Tag>\n );\n};\n\nfunction getDefaultElement(variant: TextProps['variant']): string {\n const elementMap: Record<NonNullable<TextProps['variant']>, string> = {\n body: 'p',\n caption: 'span',\n label: 'span',\n code: 'code',\n };\n\n return elementMap[variant!] || 'p';\n}\n","import React, { useRef, useState } from \"react\";\nimport { Button } from \"../action/Button\";\nimport { Text } from \"../typography/Text\";\nimport { cn } from \"../utils/cn\";\n\nexport interface ImageFieldProps {\n label?: string;\n /** Current value as a base64 data URI, or undefined when empty. */\n value?: string;\n onChange: (value: string | undefined) => void;\n /** Longest side after downscaling. */\n maxDimension?: number;\n /**\n * Ceiling for the encoded result. The server checks this too — this one is\n * here so the user finds out before saving, not so the rule is enforced.\n */\n maxBytes?: number;\n /** Preview box shape. */\n aspect?: \"square\" | \"wide\";\n helperText?: React.ReactNode;\n disabled?: boolean;\n className?: string;\n chooseLabel?: string;\n removeLabel?: string;\n /** Shown when the picked file is still too large after downscaling. */\n tooLargeLabel?: string;\n}\n\n/**\n * Pick an image and keep it inline as a base64 data URI.\n *\n * For the small brand assets that live on a row rather than in the storage app\n * — an organisation logo, a help centre favicon. Not for content: an article\n * image belongs in storage, once storage can serve a public URL.\n *\n * The canvas downscale is a courtesy, not a limit. The same ceiling is enforced\n * server-side by `assertInlineImage`, because anyone can call the API without\n * going through this field.\n */\nexport function ImageField({\n label,\n value,\n onChange,\n maxDimension = 256,\n maxBytes,\n aspect = \"square\",\n helperText,\n disabled,\n className,\n chooseLabel = \"Choose\",\n removeLabel = \"Remove\",\n tooLargeLabel = \"That image is too large.\",\n}: ImageFieldProps) {\n const inputRef = useRef<HTMLInputElement>(null);\n const [error, setError] = useState<string | null>(null);\n\n const handleSelect = async (file?: File) => {\n if (!file) return;\n setError(null);\n const encoded = await downscaleToDataUri(file, maxDimension);\n if (maxBytes && approximateBytes(encoded) > maxBytes) {\n setError(tooLargeLabel);\n return;\n }\n onChange(encoded);\n };\n\n return (\n <div className={cn(\"flex flex-col gap-1.5\", className)}>\n {label && <span className=\"text-sm font-medium text-text\">{label}</span>}\n\n <div className=\"flex items-center gap-4\">\n <div\n className={cn(\n \"flex items-center justify-center overflow-hidden rounded-md border border-border bg-surface-sunk\",\n aspect === \"square\" ? \"h-16 w-16\" : \"h-16 w-28\",\n )}\n >\n {value ? (\n <img src={value} alt=\"\" className=\"h-full w-full object-contain\" />\n ) : (\n <Text variant=\"caption\" color=\"muted\">\n —\n </Text>\n )}\n </div>\n\n <div className=\"flex flex-col gap-2\">\n <div className=\"flex gap-2\">\n <Button\n type=\"button\"\n variant=\"secondary\"\n disabled={disabled}\n onClick={() => inputRef.current?.click()}\n >\n {chooseLabel}\n </Button>\n {value && (\n <Button\n type=\"button\"\n variant=\"ghost\"\n disabled={disabled}\n onClick={() => {\n setError(null);\n onChange(undefined);\n }}\n >\n {removeLabel}\n </Button>\n )}\n </div>\n {(error || helperText) && (\n <Text variant=\"caption\" color={error ? \"error\" : \"muted\"}>\n {error ?? helperText}\n </Text>\n )}\n </div>\n </div>\n\n <input\n ref={inputRef}\n type=\"file\"\n accept=\"image/png,image/jpeg,image/webp\"\n className=\"hidden\"\n onChange={(e) => void handleSelect(e.target.files?.[0])}\n />\n </div>\n );\n}\n\n/** Roughly how many bytes a data URI's payload decodes to. */\nexport function approximateBytes(dataUri: string): number {\n const base64 = dataUri.slice(dataUri.indexOf(\",\") + 1);\n const padding = base64.endsWith(\"==\") ? 2 : base64.endsWith(\"=\") ? 1 : 0;\n return Math.floor((base64.length * 3) / 4) - padding;\n}\n\n/** Read a file, shrink it to `maxDimension` on a canvas, return a PNG data URI. */\nfunction downscaleToDataUri(file: File, maxDimension: number): Promise<string> {\n return new Promise((resolve, reject) => {\n const reader = new FileReader();\n reader.onload = () => {\n const img = new Image();\n img.onload = () => {\n const scale = Math.min(1, maxDimension / Math.max(img.width, img.height));\n const width = Math.round(img.width * scale);\n const height = Math.round(img.height * scale);\n const canvas = document.createElement(\"canvas\");\n canvas.width = width;\n canvas.height = height;\n const ctx = canvas.getContext(\"2d\");\n if (!ctx) {\n // No canvas: hand back the original rather than nothing, and let the\n // size check decide whether it is usable.\n resolve(reader.result as string);\n return;\n }\n ctx.drawImage(img, 0, 0, width, height);\n resolve(canvas.toDataURL(\"image/png\"));\n };\n img.onerror = reject;\n img.src = reader.result as string;\n };\n reader.onerror = reject;\n reader.readAsDataURL(file);\n });\n}\n","import { forwardRef, useEffect, useRef, useState } from 'react';\nimport { Calendar, ChevronLeft, ChevronRight } from 'lucide-react';\nimport { cn } from '../utils/cn';\nimport { useAnchoredPosition } from '../utils/useAnchoredPosition';\nimport { Icon } from '../content/Icon';\n\nexport interface DatePickerProps {\n /** Current date value */\n value?: Date | null;\n /** Change handler */\n onChange?: (date: Date | null) => void;\n /** Placeholder text */\n placeholder?: string;\n /** Whether the input is disabled */\n disabled?: boolean;\n /** Whether the input is required */\n required?: boolean;\n /** Input size */\n size?: 'sm' | 'md' | 'lg' | 'full';\n /** Additional CSS classes */\n className?: string;\n /** Minimum selectable date */\n minDate?: Date;\n /** Maximum selectable date */\n maxDate?: Date;\n /** Date format for display */\n format?: 'MM/dd/yyyy' | 'dd/MM/yyyy' | 'yyyy-MM-dd';\n /**\n * Also pick a time. The display gains `HH:mm`, the panel gains a time field,\n * and choosing a day keeps the time already on the value instead of resetting\n * it to midnight. Replaces a native `datetime-local`.\n */\n withTime?: boolean;\n}\n\nconst CalendarIcon = () => <Icon icon={Calendar} size=\"md\" color=\"current\" />;\nconst ChevronLeftIcon = () => <Icon icon={ChevronLeft} size=\"md\" color=\"current\" />;\nconst ChevronRightIcon = () => <Icon icon={ChevronRight} size=\"md\" color=\"current\" />;\n\n/**\n * DatePicker component with calendar popup\n */\nexport const DatePicker = forwardRef<HTMLInputElement, DatePickerProps>(({\n value,\n onChange,\n placeholder = 'Select date',\n disabled = false,\n required = false,\n size = 'md',\n className,\n minDate,\n maxDate,\n format = 'MM/dd/yyyy',\n withTime = false,\n}, ref) => {\n const [isOpen, setIsOpen] = useState(false);\n const [currentMonth, setCurrentMonth] = useState(() => value || new Date());\n const containerRef = useRef<HTMLDivElement>(null);\n const fieldRef = useRef<HTMLDivElement>(null);\n // Fixed against the field: an absolute panel is clipped by the form panel's\n // overflow and opens below the fold when the field sits near the bottom.\n //\n // Anchored on the field, not on containerRef — the panel is a child of the\n // container, so on the first open (before the fixed position lands) it counted\n // towards the container's own height and the panel placed itself a panel's\n // length too low. Closing and reopening looked fine because the measurement\n // from the previous open was still in state.\n const panelStyle = useAnchoredPosition(isOpen, fieldRef);\n\n // Close calendar when clicking outside\n useEffect(() => {\n const handleClickOutside = (event: MouseEvent) => {\n if (containerRef.current && !containerRef.current.contains(event.target as Node)) {\n setIsOpen(false);\n }\n };\n\n if (isOpen) {\n document.addEventListener('mousedown', handleClickOutside);\n }\n\n return () => {\n document.removeEventListener('mousedown', handleClickOutside);\n };\n }, [isOpen]);\n\n // Format date for display\n const formatDate = (date: Date | null): string => {\n if (!date) return '';\n\n const day = date.getDate().toString().padStart(2, '0');\n const month = (date.getMonth() + 1).toString().padStart(2, '0');\n const year = date.getFullYear();\n\n const datePart =\n format === 'dd/MM/yyyy' ? `${day}/${month}/${year}`\n : format === 'yyyy-MM-dd' ? `${year}-${month}-${day}`\n : `${month}/${day}/${year}`;\n\n return withTime ? `${datePart} ${formatTime(date)}` : datePart;\n };\n\n /** `HH:mm`, the value shape a native time input expects. */\n const formatTime = (date: Date) =>\n `${date.getHours().toString().padStart(2, '0')}:${date.getMinutes().toString().padStart(2, '0')}`;\n\n const handleTimeChange = (next: string) => {\n const [hours, minutes] = next.split(':').map(Number);\n if (Number.isNaN(hours) || Number.isNaN(minutes)) return;\n // Time can be set before a day is picked; fall back to today.\n const base = value ? new Date(value) : new Date();\n base.setHours(hours, minutes, 0, 0);\n onChange?.(base);\n };\n\n // Get calendar days for current month\n const getCalendarDays = () => {\n const year = currentMonth.getFullYear();\n const month = currentMonth.getMonth();\n\n const firstDay = new Date(year, month, 1);\n const lastDay = new Date(year, month + 1, 0);\n const startDate = new Date(firstDay);\n startDate.setDate(startDate.getDate() - firstDay.getDay());\n\n const days = [];\n const current = new Date(startDate);\n\n for (let i = 0; i < 42; i++) {\n days.push(new Date(current));\n current.setDate(current.getDate() + 1);\n }\n\n return days;\n };\n\n const handleDateSelect = (date: Date) => {\n const isInCurrentMonth = date.getMonth() === currentMonth.getMonth();\n if (!isInCurrentMonth) return;\n\n // Check min/max constraints\n if (minDate && date < minDate) return;\n if (maxDate && date > maxDate) return;\n\n if (withTime) {\n // Carry the time across, otherwise picking a day silently resets it to 00:00.\n const picked = new Date(date);\n picked.setHours(value?.getHours() ?? 0, value?.getMinutes() ?? 0, 0, 0);\n onChange?.(picked);\n // Stay open: the time still has to be set.\n return;\n }\n\n onChange?.(date);\n setIsOpen(false);\n };\n\n const handlePrevMonth = () => {\n setCurrentMonth(new Date(currentMonth.getFullYear(), currentMonth.getMonth() - 1, 1));\n };\n\n const handleNextMonth = () => {\n setCurrentMonth(new Date(currentMonth.getFullYear(), currentMonth.getMonth() + 1, 1));\n };\n\n const handleClear = () => {\n onChange?.(null);\n setIsOpen(false);\n };\n\n const inputClasses = cn(\n 'w-full border border-border-strong rounded-tile transition-colors duration-fast',\n 'bg-surface text-text',\n 'placeholder:text-text-muted',\n 'focus-visible:outline-none focus-visible:focus-ring',\n 'disabled:cursor-not-allowed disabled:bg-surface-hover disabled:text-text-disabled',\n {\n 'h-control-sm px-3 text-sm': size === 'sm',\n 'h-control-md px-3 text-base': size === 'md',\n 'h-control-lg px-3 text-base': size === 'lg',\n 'h-control-md w-full px-3 text-base': size === 'full',\n },\n className\n );\n\n const calendarDays = getCalendarDays();\n const monthNames = [\n 'January', 'February', 'March', 'April', 'May', 'June',\n 'July', 'August', 'September', 'October', 'November', 'December'\n ];\n\n return (\n <div ref={containerRef} className=\"relative\">\n {/* Input */}\n <div ref={fieldRef} className=\"relative\">\n <input\n ref={ref}\n type=\"text\"\n value={formatDate(value ?? null)}\n placeholder={placeholder}\n disabled={disabled}\n required={required}\n readOnly\n onClick={() => !disabled && setIsOpen(!isOpen)}\n className={cn(inputClasses, 'pr-10 cursor-pointer')}\n />\n <button\n type=\"button\"\n onClick={() => !disabled && setIsOpen(!isOpen)}\n disabled={disabled}\n className=\"absolute inset-y-0 right-0 flex items-center pr-3 text-text-muted hover:text-text-muted\"\n >\n <CalendarIcon />\n </button>\n </div>\n\n {/* Calendar Popup */}\n {isOpen && (\n <div style={panelStyle} className=\"fixed z-overlay overflow-auto rounded-lg border border-border bg-surface p-4 shadow-overlay min-w-panel\">\n {/* Header */}\n <div className=\"flex items-center justify-between mb-4\">\n <button\n onClick={handlePrevMonth}\n className=\"p-1 hover:bg-surface-hover rounded\"\n >\n <ChevronLeftIcon />\n </button>\n <h3 className=\"text-sm font-medium text-text\">\n {monthNames[currentMonth.getMonth()]} {currentMonth.getFullYear()}\n </h3>\n <button\n onClick={handleNextMonth}\n className=\"p-1 hover:bg-surface-hover rounded\"\n >\n <ChevronRightIcon />\n </button>\n </div>\n\n {/* Days of week */}\n <div className=\"grid grid-cols-7 gap-1 mb-2\">\n {['Su', 'Mo', 'Tu', 'We', 'Th', 'Fr', 'Sa'].map((day) => (\n <div key={day} className=\"text-xs font-medium text-text-muted text-center py-1\">\n {day}\n </div>\n ))}\n </div>\n\n {/* Calendar grid */}\n <div className=\"grid grid-cols-7 gap-1\">\n {calendarDays.map((date, index) => {\n const isCurrentMonth = date.getMonth() === currentMonth.getMonth();\n const isSelected = value && date.toDateString() === value.toDateString();\n const isToday = date.toDateString() === new Date().toDateString();\n const isDisabled =\n !isCurrentMonth ||\n (minDate && date < minDate) ||\n (maxDate && date > maxDate);\n\n return (\n <button\n key={index}\n onClick={() => !isDisabled && handleDateSelect(date)}\n disabled={isDisabled}\n className={cn(\n 'w-8 h-8 text-sm rounded transition-colors duration-fast',\n {\n 'text-text hover:bg-surface-hover':\n isCurrentMonth && !isSelected && !isDisabled,\n 'bg-accent text-accent-fg': isSelected,\n 'bg-surface-hover text-text': isToday && !isSelected,\n 'text-text-muted cursor-not-allowed': isDisabled,\n }\n )}\n >\n {date.getDate()}\n </button>\n );\n })}\n </div>\n\n {withTime && (\n <div className=\"mt-3 flex items-center gap-2 border-t border-border pt-3\">\n <label htmlFor=\"datepicker-time\" className=\"text-sm text-text-muted\">\n Tijd\n </label>\n <input\n id=\"datepicker-time\"\n type=\"time\"\n value={value ? formatTime(value) : ''}\n onChange={(e) => handleTimeChange(e.target.value)}\n className=\"h-control-sm rounded-md border border-border bg-surface-input px-2 text-sm text-text focus-visible:outline-none focus-visible:focus-ring\"\n />\n </div>\n )}\n\n {/* Footer */}\n <div className=\"flex justify-between items-center mt-4 pt-3 border-t border-border\">\n <button\n onClick={handleClear}\n className=\"text-sm text-text-muted hover:text-text\"\n >\n Clear\n </button>\n <button\n onClick={() => setIsOpen(false)}\n className=\"text-sm text-info-fg hover:underline\"\n >\n Close\n </button>\n </div>\n </div>\n )}\n </div>\n );\n}); ","import { ChevronDownIcon } from \"lucide-react\";\nimport React, { forwardRef } from \"react\";\nimport { cn } from \"../utils/cn\";\nimport { normalizeText, text } from \"../utils/text\";\nimport { useAnchoredPosition } from \"../utils/useAnchoredPosition\";\n\nexport interface SelectOption {\n value: string;\n label: string;\n disabled?: boolean;\n}\n\nexport interface SelectProps\n extends Omit<React.HTMLAttributes<HTMLDivElement>, \"onChange\"> {\n value?: string | string[];\n onChange?: (value: string | string[]) => void;\n label?: string;\n helperText?: string;\n error?: string;\n size?: \"sm\" | \"md\" | \"lg\" | \"full\";\n fullWidth?: boolean;\n /**\n * Blocks opening the menu. The trigger is a button inside the container, so\n * this has to be forwarded explicitly — spreading it with the rest of the\n * props lands it on the wrapping div, where it does nothing.\n */\n disabled?: boolean;\n options: SelectOption[];\n placeholder?: string;\n containerClassName?: string;\n labelClassName?: string;\n searchable?: boolean;\n multiple?: boolean;\n\n /** Vrije invoer toestaan (Enter of klik op “Voeg toe…”) */\n allowCreate?: boolean;\n\n /** Optioneel: zelf bepalen hoe een nieuwe optie eruit ziet */\n onCreateOption?: (label: string) => SelectOption;\n}\n\nconst selectSizes = {\n sm: \"h-control-sm px-3 text-sm\",\n md: \"h-control-md px-3 text-sm\",\n lg: \"h-control-lg px-3 text-base\",\n full: \"h-control-md w-full px-3 text-sm\",\n};\n\n/**\n * The props below say `string`, but this component is fed straight out of form\n * data, which is `any`. See {@link text} for why that has to be coerced here.\n */\nconst norm = normalizeText;\n\nexport const Select = forwardRef<HTMLDivElement, SelectProps>(\n (\n {\n label,\n helperText,\n error,\n size = \"md\",\n fullWidth = false,\n disabled = false,\n options,\n placeholder,\n containerClassName,\n labelClassName,\n className,\n id,\n searchable,\n multiple,\n value,\n onChange,\n allowCreate,\n onCreateOption,\n ...props\n },\n ref\n ) => {\n const selectId = id || `select-${Math.random().toString(36).substr(2, 9)}`;\n const hasError = Boolean(error);\n const [isOpen, setIsOpen] = React.useState(false);\n const [searchTerm, setSearchTerm] = React.useState(\"\");\n const containerRef = React.useRef<HTMLDivElement>(null);\n // Anchored to the control itself, not the container — the container also\n // holds the label, which would push the panel down by its height.\n const triggerRef = React.useRef<HTMLButtonElement>(null);\n // Fixed, not absolute: an absolute panel is clipped by the form panel's\n // overflow and runs off-screen when the field sits near the bottom.\n const panelStyle = useAnchoredPosition(isOpen, triggerRef, { matchWidth: true });\n\n // Lokale kopie van opties, waarin we ook vrije waarden kunnen bijmengen\n const [localOptions, setLocalOptions] =\n React.useState<SelectOption[]>(options);\n\n React.useImperativeHandle(ref, () => containerRef.current!);\n\n React.useEffect(() => {\n const handleClickOutside = (event: MouseEvent) => {\n if (\n containerRef.current &&\n !containerRef.current.contains(event.target as Node)\n ) {\n setIsOpen(false);\n }\n };\n document.addEventListener(\"mousedown\", handleClickOutside);\n return () =>\n document.removeEventListener(\"mousedown\", handleClickOutside);\n }, []);\n\n // Helper: check of optie (op value/label) al bestaat\n const includesOption = React.useCallback(\n (opts: SelectOption[], needle: string) =>\n opts.some(\n (o) =>\n norm(o.value) === norm(needle) || norm(o.label) === norm(needle)\n ),\n []\n );\n\n // Voeg ontbrekende current value(s) toe aan de opties\n const ensureValuesInOptions = React.useCallback(\n (baseOptions: SelectOption[], currentValue?: unknown) => {\n const out = [...baseOptions];\n\n const addIfMissing = (v?: unknown) => {\n const val = text(v).trim();\n if (!val) return;\n if (!includesOption(out, val)) {\n out.push({ value: val, label: val });\n }\n };\n\n if (Array.isArray(currentValue)) {\n currentValue.forEach(addIfMissing);\n } else {\n addIfMissing(currentValue);\n }\n\n return out;\n },\n [includesOption]\n );\n\n // Wanneer \"options\" verandert, merge + zorg dat de huidige value(s) erin staan\n React.useEffect(() => {\n setLocalOptions((prev) => {\n // Start vanuit de nieuwe options prop\n const next = [...options];\n\n // Ook eerder lokaal aangemaakte opties behouden (zonder duplicates)\n prev.forEach((opt) => {\n if (\n !includesOption(next, opt.value) &&\n !includesOption(next, opt.label)\n ) {\n next.push(opt);\n }\n });\n\n // En zorg dat de actuele value(s) aanwezig zijn\n return ensureValuesInOptions(next, value);\n });\n }, [options, value, ensureValuesInOptions, includesOption]);\n\n /**\n * The incoming value as text, so every comparison below is string-to-string.\n * Option values are strings by contract; the value comes from form data and\n * may not be — see {@link text}.\n */\n const selected = React.useMemo(\n () => (Array.isArray(value) ? value.map(text) : value == null ? undefined : text(value)),\n [value]\n );\n\n const handleSelect = (optionValue: string) => {\n if (multiple) {\n const currentValues = Array.isArray(selected) ? selected : [];\n const newValues = currentValues.includes(optionValue)\n ? currentValues.filter((v) => v !== optionValue)\n : [...currentValues, optionValue];\n onChange?.(newValues);\n } else {\n onChange?.(optionValue);\n setIsOpen(false);\n setSearchTerm(\"\");\n }\n };\n\n const selectedOption = multiple\n ? null\n : localOptions.find((o) => o.value === selected);\n\n const selectedOptions = multiple\n ? localOptions.filter(\n (o) => Array.isArray(selected) && selected.includes(o.value)\n )\n : [];\n\n const filteredOptions =\n searchable && searchTerm\n ? localOptions.filter((option) =>\n option.label.toLowerCase().includes(searchTerm.toLowerCase())\n )\n : localOptions;\n\n const canCreate =\n Boolean(allowCreate) &&\n Boolean(searchable) &&\n Boolean(searchTerm.trim()) &&\n !includesOption(localOptions, searchTerm);\n\n const createOption = (labelToCreate: string) => {\n const clean = labelToCreate.trim();\n if (!clean) return;\n\n const newOption: SelectOption = onCreateOption?.(clean) ?? {\n value: clean,\n label: clean,\n };\n\n if (\n includesOption(localOptions, newOption.value) ||\n includesOption(localOptions, newOption.label)\n ) {\n // al aanwezig; selecteer hem gewoon\n handleSelect(newOption.value);\n setSearchTerm(\"\");\n if (!multiple) setIsOpen(false);\n return;\n }\n\n setLocalOptions((prev) => [...prev, newOption]);\n handleSelect(newOption.value);\n\n setSearchTerm(\"\");\n if (!multiple) setIsOpen(false);\n };\n\n const getDisplayValue = () => {\n if (multiple) {\n if (selectedOptions.length > 0) {\n return selectedOptions.map((o) => o.label).join(\", \");\n }\n return placeholder || \"Select options\";\n }\n return selectedOption?.label || placeholder || \"Select an option\";\n };\n\n return (\n <div\n ref={containerRef}\n className={cn(\n \"relative flex flex-col\",\n fullWidth && \"w-full\",\n containerClassName\n )}\n {...props}\n >\n {label && (\n <label\n htmlFor={selectId}\n onClick={() => setIsOpen(!isOpen)}\n className={cn(\n \"block text-xs font-semibold uppercase tracking-label mb-1.5\",\n hasError\n ? \"text-danger-fg\"\n : \"text-text-muted\",\n labelClassName\n )}\n >\n {label}\n </label>\n )}\n\n <div className=\"relative\">\n <button\n ref={triggerRef}\n type=\"button\"\n id={selectId}\n disabled={disabled}\n onClick={() => setIsOpen(!isOpen)}\n className={cn(\n \"flex w-full items-center justify-between gap-2 rounded-tile border transition-colors duration-fast text-left\",\n \"focus-visible:outline-none focus-visible:focus-ring\",\n \"disabled:cursor-not-allowed disabled:bg-surface-hover disabled:text-text-disabled\",\n \"bg-surface\",\n selectSizes[size],\n hasError\n ? \"border-danger-border text-danger-fg focus-visible:focus-ring\"\n : \"border-border-strong text-text\",\n className\n )}\n >\n <span className=\"truncate flex-1 min-w-0\">{getDisplayValue()}</span>\n <ChevronDownIcon\n size={16}\n className={cn(\n \"shrink-0 opacity-60 transition-transform duration-fast\",\n isOpen && \"rotate-180\"\n )}\n />\n </button>\n\n {isOpen && (\n <div style={panelStyle} className=\"fixed z-overlay flex flex-col overflow-hidden rounded-lg border border-border bg-surface shadow-overlay\">\n {searchable && (\n <div className=\"p-2\">\n <input\n type=\"text\"\n placeholder=\"Search...\"\n value={searchTerm}\n onChange={(e) => setSearchTerm(e.target.value)}\n onKeyDown={(e) => {\n if (e.key === \"Enter\" && canCreate) {\n e.preventDefault();\n createOption(searchTerm);\n }\n }}\n className={cn(\n \"w-full px-3 py-2 text-sm rounded-md border\",\n \"text-text border-border focus-visible:outline-none focus-visible:focus-ring\"\n )}\n />\n </div>\n )}\n\n {canCreate && (\n <div\n className={cn(\n \"cursor-pointer px-3 py-1.5 text-sm\",\n \"text-info-fg hover:bg-surface-hover\"\n )}\n onClick={() => createOption(searchTerm)}\n >\n +: “{searchTerm.trim()}”\n </div>\n )}\n\n <ul className=\"min-h-0 flex-1 overflow-auto py-1\">\n {placeholder && !multiple && (\n <li\n className=\"cursor-pointer px-3 py-1.5 text-sm text-text-muted hover:bg-surface-hover\"\n onClick={() => {\n onChange?.(\"\");\n setIsOpen(false);\n }}\n >\n {placeholder}\n </li>\n )}\n {filteredOptions.map((option) => {\n const isSelected = multiple\n ? Array.isArray(selected) && selected.includes(option.value)\n : selected === option.value;\n return (\n <li\n key={option.value}\n onClick={() =>\n !option.disabled && handleSelect(option.value)\n }\n className={cn(\n \"cursor-pointer px-3 py-1.5 text-sm\",\n \"text-text\",\n option.disabled\n ? \"opacity-50 cursor-not-allowed\"\n : \"hover:bg-surface-hover\",\n isSelected && \"bg-accent-soft text-accent font-semibold\"\n )}\n >\n <div className=\"flex items-center\">\n {multiple && (\n <input\n type=\"checkbox\"\n checked={isSelected}\n readOnly\n className=\"mr-3 h-4 w-4 rounded border-border [&:not(:checked)]:bg-surface-input text-accent \"\n />\n )}\n <span>{option.label}</span>\n </div>\n </li>\n );\n })}\n </ul>\n </div>\n )}\n </div>\n\n {(error || helperText) && (\n <p\n className={cn(\n \"mt-1 text-xs\",\n hasError ? \"text-danger-fg\" : \"text-text-muted\"\n )}\n >\n {error || helperText}\n </p>\n )}\n </div>\n );\n }\n);\n\nSelect.displayName = \"Select\";\n","import React, { forwardRef } from 'react';\nimport { cn } from '../utils/cn';\n\nexport interface TextFieldProps extends Omit<React.InputHTMLAttributes<HTMLInputElement>, 'size'> {\n /**\n * The label for the input field\n */\n label?: string;\n\n /**\n * Helper text to display below the input\n */\n helperText?: string;\n\n /**\n * Error message to display when the input is invalid\n */\n error?: string;\n\n /**\n * The size of the input field\n */\n size?: 'sm' | 'md' | 'lg' | 'full';\n\n /**\n * Whether the input should take the full width of its container\n */\n fullWidth?: boolean;\n\n /**\n * Icon to display at the start of the input\n */\n startIcon?: React.ReactNode;\n\n /**\n * Icon to display at the end of the input\n */\n endIcon?: React.ReactNode;\n\n /**\n * Whether the input is in a loading state\n */\n loading?: boolean;\n\n /**\n * Additional class name for the container\n */\n containerClassName?: string;\n\n /**\n * Additional class name for the label\n */\n labelClassName?: string;\n}\n\n/** Heights come from the control tokens — inputs, buttons and selects align. */\nconst inputSizes = {\n sm: 'h-control-sm px-3 text-sm',\n md: 'h-control-md px-3 text-base',\n lg: 'h-control-lg px-3 text-base',\n full: 'h-control-md px-3 text-base',\n};\n\n/**\n * Shared with TextArea / Select / DatePicker.\n *\n * Sentence case, not the uppercase small-caps it used to be: a form is a page\n * now, and every field label shouting in caps competes with the section titles\n * beside them. Uppercase is still the section-label treatment (`tracking-label`),\n * one level up.\n */\nexport const fieldLabelClasses = 'mb-1.5 block text-sm font-medium';\n\n/**\n * Shared field frame. A resting 1px edge in `border-strong` — a form field has\n * to read as an empty box you can type in, which the lighter `border` used for\n * structural rules does not do at this size.\n */\nexport const fieldFrameClasses =\n 'block w-full rounded-tile border bg-surface-input text-text ' +\n 'transition-colors duration-fast ease-out ' +\n 'placeholder:text-text-subtle ' +\n 'focus-visible:outline-none focus-visible:focus-ring ' +\n 'disabled:cursor-not-allowed disabled:bg-surface-hover disabled:text-text-disabled';\n\n/** Resting / error edge, shared so every control agrees on what \"invalid\" looks like. */\nexport const fieldEdgeClasses = (hasError: boolean) =>\n hasError ? 'border-danger-border bg-danger-soft' : 'border-border-strong';\n\n/**\n * TextField component with theme integration and validation states\n *\n * @example\n * ```tsx\n * <TextField label=\"E-mail\" type=\"email\" placeholder=\"naam@bedrijf.nl\" />\n * <TextField label=\"Zoeken\" startIcon={<Icon icon={Search} />} />\n * <TextField label=\"Wachtwoord\" type=\"password\" error=\"Verplicht veld\" />\n * ```\n */\nexport const TextField = forwardRef<HTMLInputElement, TextFieldProps>(\n (\n {\n label,\n helperText,\n error,\n size = 'md',\n fullWidth = false,\n startIcon,\n endIcon,\n loading = false,\n containerClassName,\n labelClassName,\n className,\n id,\n ...props\n },\n ref\n ) => {\n const reactId = React.useId();\n const inputId = id || `textfield-${reactId}`;\n const hasError = Boolean(error);\n const describedBy = error || helperText ? `${inputId}-description` : undefined;\n\n return (\n <div className={cn('flex flex-col', fullWidth && 'w-full', containerClassName)}>\n {label && (\n <label\n htmlFor={inputId}\n className={cn(\n fieldLabelClasses,\n hasError ? 'text-danger-fg' : 'text-text-muted',\n labelClassName\n )}\n >\n {label}\n </label>\n )}\n\n <div className=\"relative\">\n {startIcon && (\n <span className=\"pointer-events-none absolute inset-y-0 left-0 flex items-center pl-3 text-text-muted\">\n {startIcon}\n </span>\n )}\n\n <input\n ref={ref}\n id={inputId}\n aria-invalid={hasError || undefined}\n aria-describedby={describedBy}\n className={cn(\n fieldFrameClasses,\n\n inputSizes[size],\n\n startIcon && 'pl-9',\n (endIcon || loading) && 'pr-9',\n\n fieldEdgeClasses(hasError),\n\n className\n )}\n {...props}\n />\n\n {(endIcon || loading) && (\n <span className=\"absolute inset-y-0 right-0 flex items-center pr-3 text-text-muted\">\n {loading ? (\n <span\n aria-hidden\n className=\"size-icon-md animate-spin rounded-full border-2 border-border border-t-transparent\"\n />\n ) : (\n endIcon\n )}\n </span>\n )}\n </div>\n\n {(error || helperText) && (\n <p\n id={describedBy}\n className={cn('mt-1 text-xs', hasError ? 'text-danger-fg' : 'text-text-subtle')}\n >\n {error || helperText}\n </p>\n )}\n </div>\n );\n }\n);\n\nTextField.displayName = 'TextField';\n","import { VirtualMount } from \"@opencxh/domain\";\nimport { useEffect, useState } from \"react\";\nimport { Select } from \"./Select\";\nimport { TextField } from \"./TextField\";\n\nexport interface FolderDestination {\n /** Storage folder (mount) id. */\n folderId?: string;\n /** Optional sub-path template, e.g. \"{yyyy}/{mm}/{dd}\". */\n pathTemplate?: string;\n}\n\nexport interface FolderSelectProps {\n value?: FolderDestination;\n onChange?: (value: FolderDestination) => void;\n /** Loads the selectable storage folders (the shell wires this to storage.mount). */\n onListFolders?: () => Promise<{ data: VirtualMount[] }> | undefined;\n disabled?: boolean;\n size?: \"sm\" | \"md\" | \"lg\" | \"full\";\n placeholder?: string;\n templatePlaceholder?: string;\n /** Show the sub-path template input (default true). */\n showTemplate?: boolean;\n}\n\n/**\n * Destination picker for a storage folder (+ optional sub-path template).\n * Unlike StorageInput (which picks/uploads a file), this selects *where* things\n * should be written. Used by the `type: \"folder\"` form field.\n */\nexport function FolderSelect({\n value,\n onChange,\n onListFolders,\n disabled,\n size = \"md\",\n placeholder,\n templatePlaceholder,\n showTemplate = true,\n}: FolderSelectProps) {\n const [folders, setFolders] = useState<VirtualMount[]>([]);\n\n useEffect(() => {\n let active = true;\n Promise.resolve(onListFolders?.())\n .then((res) => {\n if (active && res) setFolders(res.data ?? []);\n })\n .catch(() => {\n /* folder list unavailable */\n });\n return () => {\n active = false;\n };\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, []);\n\n const v = value ?? {};\n\n return (\n <div className=\"flex flex-col gap-2\">\n <Select\n size={size}\n fullWidth\n value={v.folderId ?? \"\"}\n options={folders.map((f) => ({ value: f.id, label: f.name }))}\n placeholder={placeholder ?? \"Select a folder\"}\n onChange={(val) => onChange?.({ ...v, folderId: val as string })}\n />\n {showTemplate && (\n <TextField\n size={size}\n disabled={disabled ?? false}\n value={v.pathTemplate ?? \"\"}\n placeholder={templatePlaceholder ?? \"Sub-path e.g. {yyyy}/{mm}/{dd} (optional)\"}\n onChange={(e) => onChange?.({ ...v, pathTemplate: e.target.value })}\n />\n )}\n </div>\n );\n}\n","import React, { forwardRef, useEffect, useMemo, useRef, useState } from \"react\";\nimport { ChevronDown, Loader2, Search } from \"lucide-react\";\n\nconst cn = (...classes: string[]) => classes.filter(Boolean).join(\" \");\n\nconst SearchIcon = (props: React.SVGProps<SVGSVGElement>) => (\n <Search {...props} strokeWidth={1.5} aria-hidden />\n);\n\nconst ChevronDownIcon = (props: React.SVGProps<SVGSVGElement>) => (\n <ChevronDown {...props} strokeWidth={1.5} aria-hidden />\n);\n\nconst inputSizes = {\n sm: \"h-control-sm px-3 text-sm\",\n md: \"h-control-md px-3 text-base\",\n lg: \"h-control-lg px-3 text-base\",\n full: \"h-control-md w-full px-3 text-base\",\n};\n\nconst iconSizes = {\n sm: \"h-4 w-4\",\n md: \"h-5 w-5\",\n lg: \"h-6 w-6\",\n full: \"h-6 w-6\",\n};\n\nexport interface SearchableTextFieldOption {\n value: string;\n label: string;\n}\n\nexport interface SearchableTextFieldProps\n extends Omit<\n React.InputHTMLAttributes<HTMLInputElement>,\n \"size\" | \"onSelect\"\n > {\n label?: string;\n helperText?: string;\n error?: string;\n size?: \"sm\" | \"md\" | \"lg\" | \"full\";\n fullWidth?: boolean;\n startIcon?: React.ReactNode;\n loading?: boolean;\n containerClassName?: string;\n labelClassName?: string;\n\n options: SearchableTextFieldOption[];\n onRemoteSearch?: (searchTerm: string) => Promise<void>;\n\n onSelect?: (value: string) => void;\n debounceTime?: number;\n /**\n * Selector-modus: toon bij openen (focus/chevron) álle opties, ook wanneer de\n * huidige waarde een reeds geselecteerde optie is. Pas zodra de gebruiker zelf\n * typt wordt er gefilterd. Handig wanneer het veld eerder een keuzelijst is dan\n * een vrije zoekopdracht (bv. een afzender-selector).\n */\n showAllOnOpen?: boolean;\n}\n\nexport const SearchableTextField = forwardRef<\n HTMLInputElement,\n SearchableTextFieldProps\n>(\n (\n {\n label,\n helperText,\n error,\n size = \"md\",\n fullWidth = false,\n startIcon = <SearchIcon />,\n loading: externalLoading = false,\n containerClassName,\n labelClassName,\n className,\n id,\n options,\n onRemoteSearch,\n onSelect,\n debounceTime = 500,\n showAllOnOpen = false,\n value: propValue,\n onChange,\n ...props\n },\n ref\n ) => {\n const inputId =\n id || `searchfield-${Math.random().toString(36).substr(2, 9)}`;\n const hasError = Boolean(error);\n const containerRef = useRef(null);\n const inputRef = useRef(null);\n\n const [inputValue, setInputValue] = useState(propValue || \"\");\n const [isOpen, setIsOpen] = useState(false);\n const [isSearchingRemote, setIsSearchingRemote] = useState(false);\n // In selector-modus: is er sinds het openen daadwerkelijk getypt? Zo niet,\n // dan tonen we de volledige lijst i.p.v. te filteren op de gekozen waarde.\n const [typedSinceOpen, setTypedSinceOpen] = useState(false);\n\n useEffect(() => {\n if (propValue !== undefined) {\n setInputValue(propValue);\n }\n }, [propValue]);\n\n const filteredOptions = useMemo(() => {\n if (showAllOnOpen && !typedSinceOpen) return options;\n if (!inputValue) return options;\n const lowerCaseInput = String(inputValue).toLowerCase();\n return options.filter((option) =>\n String(option.label).toLowerCase().includes(lowerCaseInput)\n );\n }, [inputValue, options, showAllOnOpen, typedSinceOpen]);\n\n useEffect(() => {\n if (!onRemoteSearch || !inputValue) {\n setIsSearchingRemote(false);\n return;\n }\n\n const handler = setTimeout(async () => {\n setIsSearchingRemote(true);\n try {\n await onRemoteSearch(String(inputValue));\n } catch (e) {\n console.error(\"Remote search failed:\", e);\n } finally {\n setIsSearchingRemote(false);\n }\n }, debounceTime);\n\n return () => {\n clearTimeout(handler);\n setIsSearchingRemote(false);\n };\n }, [inputValue, debounceTime, onRemoteSearch]);\n\n useEffect(() => {\n const handleClickOutside = (event: MouseEvent) => {\n if (\n containerRef.current &&\n !(containerRef.current as HTMLElement).contains(event.target as Node)\n ) {\n setIsOpen(false);\n }\n };\n document.addEventListener(\"mousedown\", handleClickOutside);\n return () =>\n document.removeEventListener(\"mousedown\", handleClickOutside);\n }, []);\n\n const handleChange = (e: React.ChangeEvent<HTMLInputElement>) => {\n const newValue = e.target.value;\n setInputValue(newValue);\n setIsOpen(true);\n setTypedSinceOpen(true);\n if (onChange) {\n onChange(e);\n }\n };\n\n const handleSelect = (option: SearchableTextFieldOption) => {\n setInputValue(option.label);\n setIsOpen(false);\n setTypedSinceOpen(false);\n if (onSelect) {\n onSelect(option.value);\n }\n };\n\n const handleFocus = () => {\n // Open dropdown alleen als er opties zijn of remote search beschikbaar is\n if (options.length > 0 || onRemoteSearch) {\n setIsOpen(true);\n setTypedSinceOpen(false);\n }\n };\n\n const loading = externalLoading || isSearchingRemote;\n\n const showDropdown = isOpen && (filteredOptions.length > 0 || loading);\n\n const resolvedRef = useMemo(() => ref || inputRef, [ref]);\n\n return (\n <div\n className={cn(\n \"flex flex-col\",\n fullWidth ? \"w-full\" : \"\",\n containerClassName || \"\",\n \"relative\"\n )}\n ref={containerRef}\n >\n {label && (\n <label\n htmlFor={inputId}\n className={cn(\n \"block text-sm font-medium mb-1\",\n hasError ? \"text-danger-fg\" : \"text-text\",\n labelClassName || \"\"\n )}\n >\n {label}\n </label>\n )}\n\n <div className=\"relative\">\n {startIcon && (\n <div className=\"absolute left-0 pl-3 flex items-center pointer-events-none h-full\">\n <span className={cn(\"text-text-muted\", iconSizes[size])}>\n {startIcon}\n </span>\n </div>\n )}\n\n <input\n ref={resolvedRef}\n id={inputId}\n value={inputValue}\n onChange={handleChange}\n onFocus={handleFocus}\n className={cn(\n // Base styles\n \"block w-full rounded-tile border bg-surface-input transition-colors duration-fast ease-out\",\n \"placeholder:text-text-subtle focus-visible:outline-none focus-visible:focus-ring\",\n \"disabled:cursor-not-allowed disabled:bg-surface-hover disabled:text-text-disabled\",\n\n // Size styles\n inputSizes[size],\n\n // Icon padding\n startIcon ? \"pl-10\" : \"\",\n \"pr-10\", // Altijd padding rechts voor de dropdown/loading icon\n\n // State styles\n hasError\n ? \"border-danger-border text-danger-fg focus-visible:focus-ring\"\n : \"border-border-strong text-text\",\n\n className || \"\"\n )}\n {...props}\n />\n\n {/* END ICON (Laden/Dropdown) */}\n <div className=\"absolute inset-y-0 right-0 pr-3 flex items-center\">\n {loading || externalLoading ? (\n // Loading Spinner\n <Loader2\n className={cn(\"animate-spin text-info-fg\", iconSizes[size])}\n aria-hidden\n />\n ) : (\n // Dropdown Chevron\n <ChevronDownIcon\n className={cn(\n \"text-text-muted cursor-pointer transition-transform\",\n iconSizes[size],\n isOpen ? \"rotate-180\" : \"rotate-0\"\n )}\n onClick={() => {\n setIsOpen((prev) => {\n if (!prev) setTypedSinceOpen(false);\n return !prev;\n });\n }}\n />\n )}\n </div>\n </div>\n\n {/* DROPDOWN LIJST */}\n {showDropdown && (\n <ul\n className=\"absolute z-10 mt-1 w-full bg-surface border border-border rounded-lg shadow-lg max-h-60 overflow-auto top-full\"\n role=\"listbox\"\n >\n {filteredOptions.length > 0 ? (\n filteredOptions.map((option: SearchableTextFieldOption) => (\n <li\n key={option.value}\n className=\"px-4 py-2 cursor-pointer text-text hover:bg-accent-soft hover:text-accent transition-colors\"\n onClick={() => handleSelect(option)}\n role=\"option\"\n aria-selected={inputValue === option.label}\n >\n {option.label}\n </li>\n ))\n ) : (\n <li className=\"px-4 py-2 text-text-muted\">\n {loading || externalLoading\n ? \"Zoeken op afstand...\"\n : \"Geen resultaten gevonden.\"}\n </li>\n )}\n </ul>\n )}\n\n {/* HELPER/ERROR TEKST */}\n {(error || helperText) && (\n <p\n className={cn(\n \"mt-1 text-xs\",\n hasError ? \"text-danger-fg\" : \"text-text-muted\"\n )}\n >\n {error || helperText}\n </p>\n )}\n\n {/* Eenvoudig voorbeeld van de huidige status voor demo */}\n {onRemoteSearch && (\n <p className=\"mt-2 text-xs text-success-fg\">\n Huidige zoekterm (niet-gedebounced): {String(inputValue)}\n </p>\n )}\n </div>\n );\n }\n);\n\nSearchableTextField.displayName = \"SearchableTextField\";\n","import { Search, X } from \"lucide-react\";\nimport React, { forwardRef } from \"react\";\nimport { Icon } from \"../content/Icon\";\nimport { cn } from \"../utils/cn\";\n\nexport interface SearchFieldProps\n extends Omit<React.InputHTMLAttributes<HTMLInputElement>, \"size\" | \"value\" | \"onChange\" | \"type\"> {\n /** Current query. Controlled — this field has no internal state. */\n value: string;\n /** Called with the new query text (not the event). */\n onValueChange: (value: string) => void;\n /**\n * Keyboard hint shown at the trailing edge while the field is empty —\n * `⌘K`, `⌘F`. Replaced by the clear button once there is a query.\n */\n hint?: string;\n /** `md` is the default control height; `sm` for a dense bar. */\n size?: \"sm\" | \"md\";\n /** Accessible name for the clear button. */\n clearLabel?: string;\n /** Classes for the plate around the input. */\n containerClassName?: string;\n}\n\n/**\n * The sunk, frameless search plate: a magnifier, the query, and either a\n * keyboard hint or a clear button. It is deliberately *not* a `TextField` —\n * a bordered box would read as one more empty input in a toolbar that already\n * has filter chips and buttons, where this is the thing you type into.\n *\n * Three places had grown their own copy of it (the nav search, the settings\n * search, the table toolbar); they share this one now.\n *\n * @example\n * ```tsx\n * <SearchField value={query} onValueChange={setQuery} placeholder=\"Zoeken\" hint=\"⌘K\" />\n * ```\n */\nexport const SearchField = forwardRef<HTMLInputElement, SearchFieldProps>(\n (\n {\n value,\n onValueChange,\n hint,\n size = \"md\",\n clearLabel = \"Clear search\",\n containerClassName,\n className,\n disabled,\n ...props\n },\n ref,\n ) => (\n <div\n className={cn(\n // No focus ring: the plate is a container, not the control, and a ring\n // around a frameless search box reads as the border it deliberately\n // does not have.\n \"flex items-center gap-2 rounded-md bg-surface-sunk px-2.5 text-text-muted\",\n \"transition-colors duration-fast ease-out\",\n size === \"sm\" ? \"h-control-sm\" : \"h-control-md\",\n disabled && \"opacity-60\",\n containerClassName,\n )}\n >\n <Icon icon={Search} size=\"md\" color=\"current\" className=\"shrink-0\" />\n\n <input\n ref={ref}\n type=\"search\"\n value={value}\n disabled={disabled}\n onChange={(event) => onValueChange(event.target.value)}\n className={cn(\n // The forms base layer hands every input a white fill, a 1px border\n // and a blue focus ring; a field that is only a caret inside a plate\n // has to switch all three off explicitly. Padding too — the base rule\n // sets 8/12px, which would push the text off the plate.\n \"min-w-0 flex-1 border-0 bg-transparent p-0 text-sm text-text shadow-none\",\n \"placeholder:text-text-subtle\",\n \"focus:border-0 focus:shadow-none focus:outline-none focus:ring-0\",\n // The UA search decorations (the WebKit cancel button) would sit\n // beside our own clear button.\n \"[&::-webkit-search-cancel-button]:appearance-none\",\n className,\n )}\n {...props}\n />\n\n {value ? (\n <button\n type=\"button\"\n aria-label={clearLabel}\n onClick={() => onValueChange(\"\")}\n className=\"grid size-4 shrink-0 cursor-pointer place-items-center rounded-xs text-text-subtle transition-colors duration-fast ease-out hover:text-text focus-visible:outline-none focus-visible:focus-ring\"\n >\n <Icon icon={X} size=\"sm\" color=\"current\" />\n </button>\n ) : (\n hint && <span className=\"shrink-0 text-xs text-text-subtle\">{hint}</span>\n )}\n </div>\n ),\n);\n\nSearchField.displayName = \"SearchField\";\n","import React, { forwardRef } from \"react\";\nimport { cn } from \"../utils/cn\";\n\nexport interface SwitchProps\n extends Omit<React.InputHTMLAttributes<HTMLInputElement>, \"type\" | \"size\" | \"checked\" | \"onChange\"> {\n /**\n * Current state. Deliberately required and never held internally: several\n * call sites drive this from an optimistic update that rolls back on a failed\n * request, and internal state would silently swallow the rollback.\n */\n checked: boolean;\n onChange: (checked: boolean) => void;\n /** Text beside the switch. Omit it and pass `aria-label` instead. */\n label?: React.ReactNode;\n disabled?: boolean;\n}\n\n/**\n * On/off switch for a setting that applies immediately.\n *\n * Use `Checkbox` instead when the value is part of a form the user submits —\n * a switch says \"this is now on\", a checkbox says \"include this when I save\".\n *\n * @example\n * ```tsx\n * <Switch checked={syncEnabled} onChange={setSyncEnabled} label=\"Agenda synchroniseren\" />\n * ```\n */\nexport const Switch = forwardRef<HTMLInputElement, SwitchProps>(\n ({ checked, onChange, label, disabled = false, className, ...props }, ref) => {\n const track = (\n <span\n aria-hidden\n className={cn(\n \"relative inline-flex size-switch-track shrink-0 items-center rounded-full\",\n \"transition-colors duration-fast ease-out\",\n checked ? \"bg-accent\" : \"bg-surface-hover\",\n disabled && \"opacity-50\"\n )}\n >\n <span\n className={cn(\n \"absolute left-0.5 size-switch-knob rounded-full bg-surface shadow-overlay\",\n \"transition-transform duration-fast ease-out\",\n checked && \"translate-switch\"\n )}\n />\n </span>\n );\n\n return (\n <label\n className={cn(\n \"inline-flex items-center gap-2\",\n disabled ? \"cursor-not-allowed\" : \"cursor-pointer\",\n className\n )}\n >\n <input\n ref={ref}\n type=\"checkbox\"\n role=\"switch\"\n checked={checked}\n disabled={disabled}\n onChange={(event) => onChange(event.target.checked)}\n className=\"peer sr-only\"\n {...props}\n />\n {/* The ring lives on the track, since the input itself is visually hidden. */}\n <span className=\"inline-flex rounded-full peer-focus-visible:focus-ring\">{track}</span>\n {label && <span className=\"text-sm text-text\">{label}</span>}\n </label>\n );\n }\n);\n\nSwitch.displayName = \"Switch\";\n","import { Check } from \"lucide-react\";\nimport React, { useEffect, useRef, useState } from \"react\";\nimport { cn } from \"../utils/cn\";\nimport { useAnchoredPosition } from \"../utils/useAnchoredPosition\";\n\nexport interface DropdownOption {\n /** Option value */\n value: string;\n /** Option label */\n label: string;\n /** Option icon */\n icon?: React.ReactNode;\n /** Whether option is disabled */\n disabled?: boolean;\n /** Whether option is a divider */\n divider?: boolean;\n /** Optional description for the option */\n description?: string;\n /** Nested sub-options */\n children?: DropdownOption[];\n}\n\nexport interface DropdownProps {\n /** Dropdown trigger element */\n trigger: React.ReactNode;\n /** Dropdown options */\n options: DropdownOption[];\n /** Selected value */\n value?: string | Record<string, string | string[]>;\n /** Change handler */\n onSelect?: (value: string, parentValue?: string) => void;\n /** Dropdown placement */\n placement?: \"bottom-start\" | \"bottom-end\" | \"top-start\" | \"top-end\";\n /** Whether dropdown is disabled */\n disabled?: boolean;\n /** Additional CSS classes */\n className?: string;\n /** Show check mark for selected option */\n showCheck?: boolean;\n /** Header text for the dropdown */\n header?: string | React.ReactNode;\n}\n\n/**\n * Dropdown component for menus and select-like interfaces\n */\nexport const Dropdown: React.FC<DropdownProps> = ({\n trigger,\n options,\n value,\n onSelect,\n placement = \"bottom-start\",\n disabled = false,\n className,\n showCheck = true,\n header,\n}) => {\n const [isOpen, setIsOpen] = useState(false);\n const [hoveredOption, setHoveredOption] = useState<\n string | Record<string, string | string[]> | null\n >(null);\n const [submenuPosition, setSubmenuPosition] = useState({ top: 0, left: 0 });\n // Menu is position:fixed (computed from the trigger) so it escapes any\n // overflow-hidden / rounded-card ancestor instead of being clipped.\n const dropdownRef = useRef<HTMLDivElement>(null);\n const triggerRef = useRef<HTMLButtonElement>(null);\n const submenuRef = useRef<HTMLDivElement>(null);\n const menuRef = useRef<HTMLDivElement>(null);\n const menuPos = useAnchoredPosition(isOpen, triggerRef, { placement });\n const hideTimeoutRef = useRef<NodeJS.Timeout | null>(null);\n\n /** Enabled option buttons in the open menu, in DOM order. */\n const menuItems = () =>\n Array.from(\n menuRef.current?.querySelectorAll<HTMLButtonElement>(\"button[data-option-value]:not(:disabled)\") ?? []\n );\n\n // Move focus into the menu when it opens, so the keyboard lands somewhere\n // useful instead of on the page behind it.\n useEffect(() => {\n if (isOpen) menuItems()[0]?.focus();\n }, [isOpen]);\n\n /** Roving focus: ↓/↑ wrap through the options, Home/End jump to the ends. */\n const handleMenuKeyDown = (event: React.KeyboardEvent<HTMLDivElement>) => {\n const keys = [\"ArrowDown\", \"ArrowUp\", \"Home\", \"End\"];\n if (!keys.includes(event.key)) return;\n\n const items = menuItems();\n if (items.length === 0) return;\n event.preventDefault();\n\n const current = items.indexOf(document.activeElement as HTMLButtonElement);\n const next =\n event.key === \"Home\" ? 0\n : event.key === \"End\" ? items.length - 1\n : event.key === \"ArrowDown\" ? (current + 1) % items.length\n : (current - 1 + items.length) % items.length;\n\n items[next]?.focus();\n };\n\n // Close dropdown when clicking outside\n useEffect(() => {\n const handleClickOutside = (event: MouseEvent) => {\n if (\n dropdownRef.current &&\n (!dropdownRef.current.contains(event.target as Node) ||\n (submenuRef.current &&\n !submenuRef.current.contains(event.target as Node)))\n ) {\n setIsOpen(false);\n setHoveredOption(null);\n if (hideTimeoutRef.current) {\n clearTimeout(hideTimeoutRef.current);\n hideTimeoutRef.current = null;\n }\n }\n };\n\n if (isOpen) {\n document.addEventListener(\"mousedown\", handleClickOutside);\n }\n\n return () => {\n document.removeEventListener(\"mousedown\", handleClickOutside);\n };\n }, [isOpen]);\n\n // Close dropdown on escape key\n useEffect(() => {\n const handleEscape = (event: KeyboardEvent) => {\n if (event.key === \"Escape\") {\n setIsOpen(false);\n setHoveredOption(null);\n // Hand focus back to the trigger; otherwise it falls to <body> and the\n // keyboard user loses their place.\n triggerRef.current?.focus();\n if (hideTimeoutRef.current) {\n clearTimeout(hideTimeoutRef.current);\n hideTimeoutRef.current = null;\n }\n }\n };\n\n if (isOpen) {\n document.addEventListener(\"keydown\", handleEscape);\n }\n\n return () => {\n document.removeEventListener(\"keydown\", handleEscape);\n };\n }, [isOpen]);\n\n // Calculate submenu position when hovering over an option with children\n useEffect(() => {\n if (hoveredOption && dropdownRef.current) {\n const hoveredElement = dropdownRef.current.querySelector(\n `[data-option-value=\"${hoveredOption}\"]`\n );\n if (hoveredElement) {\n const rect = hoveredElement.getBoundingClientRect();\n setSubmenuPosition({\n top: rect.top,\n left: rect.right + 8,\n });\n }\n }\n }, [hoveredOption]);\n\n // Cleanup timeout on unmount\n useEffect(() => {\n return () => {\n if (hideTimeoutRef.current) {\n clearTimeout(hideTimeoutRef.current);\n }\n };\n }, []);\n\n const handleTriggerClick = (event: React.MouseEvent<HTMLButtonElement>) => {\n event.stopPropagation();\n if (disabled) return;\n setIsOpen(!isOpen);\n setHoveredOption(null);\n if (hideTimeoutRef.current) {\n clearTimeout(hideTimeoutRef.current);\n hideTimeoutRef.current = null;\n }\n };\n\n const handleOptionClick = (\n event: React.MouseEvent<HTMLButtonElement>,\n option: DropdownOption,\n parentValue?: string\n ) => {\n event.stopPropagation();\n if (!option.disabled && !option.divider) {\n // Only close dropdown if option has no children\n if (!option.children || option.children.length === 0) {\n onSelect?.(option.value, parentValue);\n setIsOpen(false);\n setHoveredOption(null);\n }\n }\n };\n\n const handleOptionHover = (option: DropdownOption) => {\n // Clear any existing timeout\n if (hideTimeoutRef.current) {\n clearTimeout(hideTimeoutRef.current);\n hideTimeoutRef.current = null;\n }\n\n if (option.children && option.children.length > 0) {\n setHoveredOption(option.value);\n } else {\n setHoveredOption(null);\n }\n };\n\n const handleOptionLeave = (option: DropdownOption) => {\n // Only hide if the option has children, and add a small delay\n if (option.children && option.children.length > 0) {\n hideTimeoutRef.current = setTimeout(() => {\n setHoveredOption(null);\n }, 150); // 150ms delay\n } else {\n setHoveredOption(null);\n }\n };\n\n const handleSubmenuOptionClick = (\n event: React.MouseEvent<HTMLButtonElement>,\n option: DropdownOption,\n parentValue?: string\n ) => {\n event.stopPropagation();\n if (!option.disabled && !option.divider) {\n onSelect?.(option.value, parentValue);\n setIsOpen(false);\n setHoveredOption(null);\n }\n };\n\n const dropdownClasses = cn(\n \"fixed z-overlay min-w-menu bg-surface rounded-lg shadow-overlay border border-border\",\n \"max-h-60 overflow-auto\"\n );\n\n const submenuClasses = cn(\n \"fixed z-overlay min-w-menu bg-surface rounded-lg shadow-overlay border border-border\",\n \"max-h-60 overflow-auto\"\n );\n\n return (\n <div\n ref={dropdownRef}\n className={cn(\n \"relative flex flex-row items-center justify-center rounded-lg hover:bg-surface-hover\",\n className\n )}\n >\n {/* Trigger */}\n <button\n ref={triggerRef}\n onClick={handleTriggerClick}\n disabled={disabled}\n aria-haspopup=\"menu\"\n aria-expanded={isOpen}\n className={cn(\"inline-flex items-center justify-center\", {\n \"opacity-50 cursor-not-allowed\": disabled,\n })}\n >\n {trigger}\n </button>\n\n {/* Dropdown menu */}\n {isOpen && (\n <div ref={menuRef} className={dropdownClasses} style={menuPos} onKeyDown={handleMenuKeyDown}>\n <div className=\"p-2\" role=\"menu\">\n {/* Header */}\n {header && (\n typeof header === \"string\" ? (\n <div className=\"text-xs font-medium text-text-muted uppercase tracking-label px-3 py-2\">\n {header}\n </div>\n ) : (\n header\n )\n )}\n\n {options.map((option, index) => {\n if (option.divider) {\n return (\n <div\n key={`divider-${index}`}\n className=\"border-t border-border my-2\"\n />\n );\n }\n\n const hasChildren = option.children && option.children.length > 0;\n const isHovered = hoveredOption === option.value;\n\n return (\n <div key={option.value} className=\"relative group\">\n <button\n data-option-value={option.value}\n role=\"menuitem\"\n aria-haspopup={hasChildren ? \"menu\" : undefined}\n onClick={(event) => handleOptionClick(event, option)}\n onMouseEnter={() => handleOptionHover(option)}\n onMouseLeave={() => handleOptionLeave(option)}\n disabled={option.disabled}\n className={cn(\n \"flex w-full items-center justify-between rounded-md px-3 py-1.5 text-sm text-text transition-colors duration-fast ease-out hover:bg-surface-hover focus-visible:outline-none focus-visible:focus-ring\",\n {\n \"opacity-50 cursor-not-allowed\": option.disabled,\n \"bg-surface-hover\":\n isHovered && hasChildren,\n }\n )}\n >\n <div className=\"flex items-center space-x-2 min-w-0\">\n {option.icon && (\n <span className=\"flex-shrink-0\">{option.icon}</span>\n )}\n <div className=\"flex flex-col items-start min-w-0\">\n <span className=\"font-base truncate\">\n {option.label}\n </span>\n {option.description && (\n <span className=\"text-xs text-text-muted\">\n {option.description}\n </span>\n )}\n </div>\n </div>\n\n <div className=\"flex items-center space-x-2\">\n {showCheck && value === option.value && (\n <Check className=\"size-icon-md shrink-0 text-success-fg\" aria-hidden />\n )}\n {hasChildren && (\n <span className=\"text-text-muted text-xs\">\n ▶\n </span>\n )}\n </div>\n </button>\n\n {/* Nested submenu */}\n {hasChildren && isHovered && (\n <div\n ref={submenuRef}\n className={submenuClasses}\n style={{\n top: `${submenuPosition.top}px`,\n left: `${submenuPosition.left}px`,\n }}\n onMouseEnter={() => {\n // Clear any pending hide timeout\n if (hideTimeoutRef.current) {\n clearTimeout(hideTimeoutRef.current);\n hideTimeoutRef.current = null;\n }\n setHoveredOption(option.value);\n }}\n onMouseLeave={() => {\n // Add a small delay before hiding\n hideTimeoutRef.current = setTimeout(() => {\n setHoveredOption(null);\n }, 150);\n }}\n >\n <div className=\"p-2\">\n {option.children!.map((childOption, childIndex) => {\n if (childOption.divider) {\n return (\n <div\n key={`divider-${childIndex}`}\n className=\"border-t border-border my-2\"\n />\n );\n }\n\n const isSelected =\n (typeof value === \"object\" &&\n value[option.value] &&\n value[option.value].includes(\n childOption.value\n )) ||\n value === childOption.value;\n\n return (\n <button\n key={childOption.value}\n onClick={(event) =>\n handleSubmenuOptionClick(\n event,\n childOption,\n option.value\n )\n }\n disabled={childOption.disabled}\n className={cn(\n \"flex w-full items-center justify-between rounded-md px-3 py-1.5 text-sm text-text transition-colors duration-fast ease-out hover:bg-surface-hover\",\n {\n \"opacity-50 cursor-not-allowed\":\n childOption.disabled,\n }\n )}\n >\n <div className=\"flex items-center space-x-2 min-w-0\">\n {childOption.icon && (\n <span className=\"flex-shrink-0\">\n {childOption.icon}\n </span>\n )}\n <div className=\"flex flex-col items-start min-w-0\">\n <span className=\"font-base truncate\">\n {childOption.label}\n </span>\n {childOption.description && (\n <span className=\"text-xs text-text-muted\">\n {childOption.description}\n </span>\n )}\n </div>\n </div>\n\n {showCheck && isSelected && (\n <Check className=\"size-icon-md shrink-0 text-success-fg\" aria-hidden />\n )}\n </button>\n );\n })}\n </div>\n </div>\n )}\n </div>\n );\n })}\n\n {/* Footer with count */}\n {(() => {\n const totalOptions = options.reduce((count, option) => {\n if (option.divider) return count;\n const childCount = option.children\n ? option.children.filter((child) => !child.divider).length\n : 0;\n return count + 1 + childCount;\n }, 0);\n\n return (\n totalOptions > 1 && (\n <div className=\"border-t border-border mt-2 pt-2\">\n <div className=\"text-xs text-text-muted px-3 py-1\">\n {totalOptions} options available\n </div>\n </div>\n )\n );\n })()}\n </div>\n </div>\n )}\n </div>\n );\n};\n","import { ChevronLeft } from \"lucide-react\";\nimport React from \"react\";\nimport { Button, type ButtonProps } from \"../action/Button\";\nimport { SplitButton } from \"../action/SplitButton\";\nimport { cn } from \"../utils/cn\";\nimport { Icon } from \"./Icon\";\nimport type { PageHeaderAction } from \"./PageHeader\";\n\nexport interface PageToolbarActionsProps {\n actions: PageHeaderAction[];\n /**\n * Variant for actions that do not name one. `secondary` (a sunk plate) suits\n * a detail page's Cancel/Save pair; a list toolbar passes `ghost`, because\n * there the plate would collide with the sunk search field beside it.\n */\n defaultVariant?: ButtonProps[\"variant\"];\n className?: string;\n}\n\n/**\n * The action cluster shared by `PageToolbar` and the table toolbar, so a\n * \"New …\" button looks the same wherever a view decides to put it.\n */\nexport const PageToolbarActions: React.FC<PageToolbarActionsProps> = ({\n actions,\n defaultVariant = \"secondary\",\n className,\n}) => {\n if (actions.length === 0) return null;\n\n return (\n <div className={cn(\"flex flex-wrap items-center gap-2\", className)}>\n {actions.map((action) =>\n action.render ? (\n <React.Fragment key={action.id}>{action.render()}</React.Fragment>\n ) : action.splitOptions && action.splitOptions.length > 0 ? (\n <SplitButton\n key={action.id}\n label={action.label}\n onClick={action.onClick}\n icon={action.icon}\n variant={action.variant === \"primary\" ? \"primary\" : \"secondary\"}\n options={action.splitOptions}\n disabled={action.disabled}\n />\n ) : (\n <Button\n key={action.id}\n variant={action.variant ?? defaultVariant}\n onClick={(e) => {\n e.stopPropagation();\n (e.target as HTMLButtonElement).blur();\n action.onClick();\n }}\n disabled={action.disabled}\n leftIcon={action.icon}\n >\n {action.label}\n </Button>\n )\n )}\n </div>\n );\n};\n\nexport interface PageToolbarProps {\n /** Right-aligned action buttons */\n actions?: PageHeaderAction[];\n /** Renders a ghost back button on the left */\n onBack?: () => void;\n /** Back button label (visually hidden on small screens) */\n backLabel?: string;\n /** Additional CSS classes */\n className?: string;\n /** Padding on the left and right of the toolbar */\n padding?: \"none\" | \"sm\" | \"md\" | \"lg\";\n /** Optional extra content placed between back button and actions */\n children?: React.ReactNode;\n}\n\nconst paddingClasses = {\n none: \"p-0\",\n sm: \"p-2\",\n md: \"px-5 py-4\",\n lg: \"p-6\",\n};\n\n/**\n * Thin action-bar for views that already have a host header (e.g. a settings\n * page or a detail view). Renders an optional back button on the left and\n * action buttons on the right. Use `PageHeader` when the view needs its own\n * title/breadcrumbs — and for a list, put the actions on the `Table` toolbar\n * instead, next to the search and filters they apply to.\n */\nexport const PageToolbar: React.FC<PageToolbarProps> = ({\n actions = [],\n onBack,\n backLabel = \"Back\",\n className,\n padding = \"md\",\n children,\n}) => {\n return (\n <div className={cn(\"flex items-center gap-2\", paddingClasses[padding], className)}>\n {onBack && (\n <Button\n variant=\"secondary\"\n onClick={onBack}\n aria-label={backLabel}\n leftIcon={<Icon icon={ChevronLeft} size=\"sm\" />}\n iconOnly\n />\n )}\n\n {children && <div className=\"min-w-0 flex-1\">{children}</div>}\n\n <PageToolbarActions actions={actions} className={cn(!children && \"ml-auto\")} />\n </div>\n );\n};\n","import { ChevronDown, ChevronLeft, ChevronRight, ChevronUp, Ellipsis } from \"lucide-react\";\nimport React, {\n useCallback,\n useEffect,\n useMemo,\n useRef,\n useState,\n} from \"react\";\nimport { Button } from \"../action/Button\";\nimport { FilterChip } from \"../action/FilterChip\";\nimport { Checkbox } from \"../input/Checkbox\";\nimport { DatePicker } from \"../input/DatePicker\";\nimport { SearchField } from \"../input/SearchField\";\nimport { Dropdown } from \"../overlays/Dropdown\";\nimport { cn } from \"../utils/cn\";\nimport { Icon } from \"./Icon\";\nimport type { PageHeaderAction } from \"./PageHeader\";\nimport { PageToolbarActions } from \"./PageToolbar\";\n\nexport interface TableColumn<T = any> {\n /** Unique column identifier */\n id: string;\n /** Column header text */\n header: string;\n /** Data accessor - can be string key or function */\n accessor: keyof T | ((row: T) => any);\n /** Custom cell renderer */\n cell?: (value: any, row: T, index: number) => React.ReactNode;\n /** Column width */\n width?: string | number;\n /** Whether column is sortable */\n sortable?: boolean;\n /** Whether column is searchable */\n searchable?: boolean;\n /** Column alignment */\n align?: \"left\" | \"center\" | \"right\";\n /** Whether column is sticky */\n sticky?: \"left\" | \"right\";\n /** Custom header renderer */\n headerCell?: () => React.ReactNode;\n}\n\nexport interface TableAction<T = any> {\n /** Action identifier */\n id: string;\n /** Action label */\n label: string;\n /** Action icon */\n icon?: React.ReactNode;\n /** Action handler */\n onClick: (row: T, index: number) => void;\n /** Whether action is disabled for this row */\n disabled?: (row: T) => boolean;\n /** Action variant */\n variant?: \"primary\" | \"secondary\" | \"outline\" | \"ghost\" | \"destructive\";\n}\n\nexport interface TableFilter {\n /** Filter identifier */\n id: string;\n /** Filter label */\n label: string;\n /** Filter type */\n type?: \"select\" | \"date\" | \"dateRange\";\n /** Leading icon on the chip — what the filter is about, at a glance. */\n icon?: React.ReactNode;\n /** Filter options (for select type) */\n options?: Array<{ value: string; label: string }>;\n /** Current filter value */\n value?: string | Date | null | string[];\n /** Filter change handler */\n onChange: (value: string | Date | null | string[]) => void;\n /** Placeholder text */\n placeholder?: string;\n /** Whether filter is multi-select */\n multiSelect?: boolean;\n}\n\n/**\n * `TableFilter.onChange` covers every filter `type` in one signature, so a\n * handler written for the type it is actually attached to does not fit it\n * (parameters are contravariant). These adapters bridge that without pushing a\n * cast into every call site.\n *\n * The fallbacks are unreachable in practice — a `type: \"date\"` filter only ever\n * emits `Date | null`, a single `type: \"select\"` only ever a string — but they\n * keep the coercion explicit instead of asserting it away.\n */\nexport const dateFilterHandler =\n (fn: (value: Date | null) => void): TableFilter[\"onChange\"] =>\n (value) => fn(value instanceof Date ? value : null);\n\nexport const selectFilterHandler =\n (fn: (value: string) => void): TableFilter[\"onChange\"] =>\n (value) => fn(typeof value === \"string\" ? value : \"\");\n\nexport interface TableProps<T = any> {\n /** Table data */\n data: T[];\n /** Column definitions */\n columns: TableColumn<T>[];\n /** Loading state */\n loading?: boolean;\n /** Whether table is searchable */\n searchable?: boolean;\n /** Search placeholder text */\n searchPlaceholder?: string;\n /**\n * Take over the query. Pass this pair when the page already filters its own\n * data — across fields no column exposes, or together with filters of its\n * own — and only wants the search plate to sit in the toolbar where the\n * design puts it. The built-in column search then stays out of the way;\n * without them the table owns both the box and the filtering.\n */\n searchValue?: string;\n onSearchChange?: (value: string) => void;\n /** Table filters */\n filters?: TableFilter[];\n /**\n * Buttons for the toolbar above the table — \"New …\", import, export. This is\n * where a list's own actions belong: the page header names the page, the\n * table owns what you do to it.\n */\n toolbarActions?: PageHeaderAction[];\n /** Whether table has pagination */\n paginated?: boolean;\n /** Rows per page. Fixed — the footer is a summary and a page list, nothing to set. */\n defaultPageSize?: number;\n /** Row actions */\n actions?: TableAction<T>[];\n /** Row click handler */\n onRowClick?: (row: T, index: number) => void;\n /** Row selection */\n selectable?: boolean;\n /** Selected rows */\n selectedRows?: T[];\n /** Selection change handler */\n onSelectionChange?: (selectedRows: T[]) => void;\n /** Row key accessor */\n getRowKey?: (row: T, index: number) => string | number;\n /** Empty state content */\n emptyContent?: React.ReactNode;\n /**\n * Left-hand line under the table. Defaults to the range/total count on a\n * paginated table; pass a node to say it in the app's own words (\"9 of 1,284\n * contacts\"), which also gives an unpaginated table that one line.\n */\n footerSummary?: React.ReactNode;\n /** Row density. `md` is the default data row; `sm` for a dense inline list. */\n size?: \"sm\" | \"md\" | \"lg\";\n /** Whether to show row hover */\n hoverable?: boolean;\n /** Additional CSS classes */\n className?: string;\n /** Custom row className */\n rowClassName?: (row: T, index: number) => string;\n /**\n * Tint the header row so it reads as a column strip rather than a first row.\n * On by default. Turn it off for a table that already sits on a tinted\n * surface, where a second wash just muddies the edge.\n */\n headerBackground?: boolean;\n /** Horizontal padding inside the table box. */\n padding?: \"none\" | \"sm\" | \"md\" | \"lg\";\n}\n\n/** Cell padding — uniform across columns, so the grid reads as a grid. */\nconst cellPadding = {\n none: \"px-0\",\n sm: \"px-2\",\n md: \"px-3.5\",\n lg: \"px-5\",\n};\n\nconst rowHeights = {\n sm: \"h-row-lg\",\n md: \"h-row-xl\",\n lg: \"h-14\",\n};\n\n/** How many placeholder rows to draw while the data is on its way. */\nconst SKELETON_ROWS = 8;\n\n/** Uneven cell widths, so the placeholder reads as text and not as a bar chart. */\nconst SKELETON_WIDTHS = [\"62%\", \"44%\", \"74%\", \"52%\", \"68%\", \"48%\", \"80%\", \"56%\"];\n\ninterface SortState {\n column: string | null;\n direction: \"asc\" | \"desc\" | null;\n}\n\ninterface PaginationState {\n page: number;\n pageSize: number;\n}\n\n/**\n * Page buttons around the current page: first, last, a window of neighbours,\n * and an ellipsis wherever that skips something.\n */\nfunction pageWindow(current: number, total: number): Array<number | \"gap\"> {\n if (total <= 7) return Array.from({ length: total }, (_, i) => i);\n\n const pages = new Set([0, total - 1, current - 1, current, current + 1]);\n const sorted = [...pages].filter((p) => p >= 0 && p < total).sort((a, b) => a - b);\n\n const out: Array<number | \"gap\"> = [];\n sorted.forEach((page, index) => {\n if (index > 0 && page - (sorted[index - 1] as number) > 1) out.push(\"gap\");\n out.push(page);\n });\n return out;\n}\n\n/** One filter, as a chip that opens its own value list. */\nconst FilterMenu = (props: TableFilter) => {\n const values = Array.isArray(props.value)\n ? props.value\n : props.value != null && props.value !== \"\" && props.value !== \"all\"\n ? [props.value]\n : [];\n\n if (props.type === \"date\") {\n const active = props.value instanceof Date;\n return (\n <DatePicker\n value={props.value as Date | null}\n onChange={(date) => props.onChange(date)}\n placeholder={props.placeholder || props.label}\n // Active is a soft fill, like every other filter — an outline in the\n // accent hue was left over from the blue-accent design and read as a\n // focus ring on a field nobody had focused.\n className={cn(\"min-w-40\", active && \"bg-info-soft text-info-fg\")}\n />\n );\n }\n\n const labelOf = (value: unknown) =>\n props.options?.find((option) => option.value === value)?.label ?? String(value);\n\n const isSelected = (value: string) =>\n Array.isArray(props.value) ? props.value.includes(value) : props.value === value;\n\n const pick = (value: string) => {\n if (!props.multiSelect) return props.onChange(value);\n const current = Array.isArray(props.value) ? props.value : [];\n props.onChange(\n current.includes(value) ? current.filter((v) => v !== value) : [...current, value],\n );\n };\n\n const active = values.length > 0;\n\n return (\n <FilterChip\n tone=\"outline\"\n caret\n icon={props.icon}\n active={active}\n label={active ? `${props.label}: ${values.map(labelOf).join(\", \")}` : props.label}\n title={props.label}\n onClear={() => props.onChange(props.multiSelect ? [] : \"all\")}\n menu={(close) => (\n <div role=\"listbox\" className=\"flex flex-col\">\n {props.options?.map((option) => (\n <button\n key={option.value}\n type=\"button\"\n role=\"option\"\n aria-selected={isSelected(option.value)}\n onClick={() => {\n pick(option.value);\n if (!props.multiSelect) close();\n }}\n className={cn(\n \"flex cursor-pointer items-center gap-2 rounded-md px-2.5 py-1.5 text-left text-sm\",\n \"transition-colors duration-fast ease-out hover:bg-surface-hover\",\n \"focus-visible:outline-none focus-visible:focus-ring\",\n isSelected(option.value) ? \"font-medium text-text\" : \"text-text-muted\",\n )}\n >\n {option.label}\n </button>\n ))}\n </div>\n )}\n />\n );\n};\n\n/**\n * Data table: a bordered box with a tinted column strip, a toolbar above it\n * (search, filters, the list's own actions) and a summary + paginator below.\n */\nexport const Table = <T extends Record<string, any>>({\n data,\n columns,\n loading = false,\n searchable = false,\n searchPlaceholder = \"Search...\",\n searchValue,\n onSearchChange,\n filters = [],\n toolbarActions = [],\n paginated = false,\n defaultPageSize = 10,\n actions = [],\n onRowClick,\n selectable = false,\n selectedRows = [],\n onSelectionChange,\n getRowKey = (row, index) => index,\n emptyContent,\n footerSummary,\n size = \"md\",\n hoverable = true,\n padding = \"md\",\n className,\n rowClassName,\n headerBackground = true,\n}: TableProps<T>) => {\n const [internalSearch, setInternalSearch] = useState(\"\");\n const controlledSearch = searchValue !== undefined;\n const searchTerm = controlledSearch ? searchValue : internalSearch;\n const setSearchTerm = onSearchChange ?? setInternalSearch;\n const [sortState, setSortState] = useState<SortState>({\n column: null,\n direction: null,\n });\n const [pagination, setPagination] = useState<PaginationState>({\n page: 0,\n pageSize: defaultPageSize,\n });\n\n const tableRef = useRef<HTMLTableElement>(null);\n\n // Memoized filtered data\n const filteredData = useMemo(() => {\n let result = data;\n\n // Apply search filter — unless the owner took over the query, in which case\n // the data arriving here is already filtered and doing it again would\n // narrow it to whatever the columns happen to expose.\n if (searchable && !controlledSearch && searchTerm.trim()) {\n const searchableColumns = columns.filter(\n (col) => col.searchable !== false\n );\n const lowerSearchTerm = searchTerm.toLowerCase();\n\n result = result.filter((row) => {\n return searchableColumns.some((column) => {\n const value =\n typeof column.accessor === \"function\"\n ? column.accessor(row)\n : row[column.accessor];\n\n return String(value || \"\")\n .toLowerCase()\n .includes(lowerSearchTerm);\n });\n });\n }\n\n // Apply column filters\n filters.forEach((filter) => {\n if (filter.value && filter.value !== \"all\") {\n result = result.filter((row) => {\n const column = columns.find((col) => col.id === filter.id);\n if (!column) return true;\n\n const value =\n typeof column.accessor === \"function\"\n ? column.accessor(row)\n : row[column.accessor];\n\n return String(value || \"\") === filter.value;\n });\n }\n });\n\n return result;\n }, [data, searchTerm, controlledSearch, columns, searchable, filters]);\n\n // Memoized sorted data\n const sortedData = useMemo(() => {\n if (!sortState.column || !sortState.direction) return filteredData;\n\n const column = columns.find((col) => col.id === sortState.column);\n if (!column) return filteredData;\n\n return [...filteredData].sort((a, b) => {\n const aValue =\n typeof column.accessor === \"function\"\n ? column.accessor(a)\n : a[column.accessor];\n const bValue =\n typeof column.accessor === \"function\"\n ? column.accessor(b)\n : b[column.accessor];\n\n let comparison = 0;\n\n if (aValue < bValue) comparison = -1;\n else if (aValue > bValue) comparison = 1;\n\n return sortState.direction === \"desc\" ? -comparison : comparison;\n });\n }, [filteredData, sortState, columns]);\n\n // Memoized paginated data\n const paginatedData = useMemo(() => {\n if (!paginated) return sortedData;\n\n const startIndex = pagination.page * pagination.pageSize;\n const endIndex = startIndex + pagination.pageSize;\n return sortedData.slice(startIndex, endIndex);\n }, [sortedData, pagination, paginated]);\n\n // Handle sorting\n const handleSort = useCallback(\n (columnId: string) => {\n const column = columns.find((col) => col.id === columnId);\n if (!column?.sortable) return;\n\n setSortState((prev) => {\n if (prev.column !== columnId) {\n return { column: columnId, direction: \"asc\" };\n }\n if (prev.direction === \"asc\") {\n return { column: columnId, direction: \"desc\" };\n }\n return { column: null, direction: null };\n });\n },\n [columns]\n );\n\n // Handle pagination\n const handlePageChange = useCallback((newPage: number) => {\n setPagination((prev) => ({ ...prev, page: newPage }));\n }, []);\n\n // Handle selection\n const handleRowSelection = useCallback(\n (row: T, checked: boolean) => {\n if (!onSelectionChange) return;\n\n const rowKey = getRowKey(row, 0);\n if (checked) {\n onSelectionChange([...selectedRows, row]);\n } else {\n onSelectionChange(\n selectedRows.filter(\n (_, i) => getRowKey(selectedRows[i], i) !== rowKey\n )\n );\n }\n },\n [selectedRows, onSelectionChange, getRowKey]\n );\n\n const handleSelectAll = useCallback(\n (checked: boolean) => {\n if (!onSelectionChange) return;\n onSelectionChange(checked ? [...paginatedData] : []);\n },\n [paginatedData, onSelectionChange]\n );\n\n // Reset pagination when data changes\n useEffect(() => {\n setPagination((prev) => ({ ...prev, page: 0 }));\n }, [searchTerm, sortState]);\n\n // Separate effect for filters to avoid infinite loops\n useEffect(() => {\n setPagination((prev) => ({ ...prev, page: 0 }));\n }, [filters.map((f) => f.value).join(\",\")]);\n\n // Calculate pagination info\n const totalItems = sortedData.length;\n const totalPages = Math.ceil(totalItems / pagination.pageSize);\n const startItem = pagination.page * pagination.pageSize + 1;\n const endItem = Math.min(startItem + pagination.pageSize - 1, totalItems);\n\n // Check if all visible rows are selected\n const allVisibleSelected =\n paginatedData.length > 0 &&\n paginatedData.every((row) => {\n const rowKey = getRowKey(row, 0);\n return selectedRows.some(\n (selectedRow, i) => getRowKey(selectedRow, i) === rowKey\n );\n });\n\n const someVisibleSelected = paginatedData.some((row) => {\n const rowKey = getRowKey(row, 0);\n return selectedRows.some(\n (selectedRow, i) => getRowKey(selectedRow, i) === rowKey\n );\n });\n\n const pad = cellPadding[padding];\n\n // Sticky cells need the same fill as the strip they sit in, otherwise the\n // frozen column shows the page through while the rest of the row is tinted.\n const headerFill = headerBackground ? \"bg-surface-sunk\" : \"bg-surface\";\n\n const cellClasses = cn(\"text-text\", pad);\n const showToolbar = searchable || filters.length > 0 || toolbarActions.length > 0;\n const showPaginator = paginated && totalItems > 0;\n const showFooter = showPaginator || footerSummary !== undefined;\n\n return (\n <div className={cn(\"flex min-w-0 flex-col\", className)}>\n {showToolbar && (\n <div className=\"flex flex-wrap items-center gap-2 pb-3\">\n {searchable && (\n <SearchField\n value={searchTerm}\n onValueChange={setSearchTerm}\n placeholder={searchPlaceholder}\n containerClassName=\"w-full sm:w-66\"\n />\n )}\n\n {filters.map((filter) => (\n <FilterMenu key={filter.id} {...filter} />\n ))}\n\n {toolbarActions.length > 0 && (\n <PageToolbarActions actions={toolbarActions} className=\"ml-auto\" />\n )}\n </div>\n )}\n\n {/* A bordered box, not a bare grid: the table has to hold its own edge\n now that the page around it is one undivided card. */}\n <div className=\"relative w-full overflow-x-auto rounded-lg ring-1 ring-border\">\n {/**\n * The skeleton lives in the tbody, not above the table.\n *\n * It used to render a whole `ContentLoading` — which defaults to\n * `variant=\"page\"`, so a `<main>` landmark with page padding appeared\n * *inside* this box — centred above a `<thead>` whose headers were\n * suppressed. The result had neither the table's columns nor its row\n * height, and the real rows then shoved everything into place.\n *\n * The headers are known before the data is, so they stay; only the rows\n * are unknown, and those are drawn at row height in the real columns.\n */}\n <table ref={tableRef} className=\"min-w-full border-collapse text-base text-text\">\n <thead className={cn(headerFill, \"h-control-lg\")}>\n <tr>\n {/* Selection Column */}\n {selectable && (\n <th className={cn(cellClasses, \"w-10\")}>\n <Checkbox\n size=\"sm\"\n checked={allVisibleSelected}\n indeterminate={someVisibleSelected && !allVisibleSelected}\n onChange={(e) => handleSelectAll(e.target.checked)}\n aria-label=\"Select all rows\"\n />\n </th>\n )}\n\n {/* Data Columns */}\n {columns.map((column) => (\n <th\n key={column.id}\n className={cn(\n cellClasses,\n \"text-xs font-semibold uppercase tracking-label text-text-muted\",\n \"group\",\n {\n \"text-left\": column.align === \"left\" || !column.align,\n \"text-center\": column.align === \"center\",\n \"text-right\": column.align === \"right\",\n \"cursor-pointer select-none\": column.sortable,\n [`sticky left-0 ${headerFill}`]:\n column.sticky === \"left\",\n [`sticky right-0 ${headerFill}`]:\n column.sticky === \"right\",\n },\n )}\n style={{ width: column.width }}\n onClick={() => column.sortable && handleSort(column.id)}\n >\n <div className=\"flex items-center gap-1.5\">\n {column.headerCell ? column.headerCell() : column.header}\n {column.sortable && (\n <Icon\n icon={\n sortState.column === column.id && sortState.direction === \"desc\"\n ? ChevronDown\n : ChevronUp\n }\n size=\"xs\"\n className={cn(\n \"transition-opacity duration-fast ease-out\",\n sortState.column === column.id\n ? \"text-text opacity-100\"\n : \"text-text-subtle opacity-0 group-hover:opacity-100\",\n )}\n />\n )}\n </div>\n </th>\n ))}\n\n {/* Actions Column */}\n {actions.length > 0 && (\n <th className={cn(cellClasses, \"w-10\")}>\n <span className=\"sr-only\">Actions</span>\n </th>\n )}\n </tr>\n </thead>\n\n <tbody>\n {loading\n ? Array.from({ length: SKELETON_ROWS }).map((_, rowIndex) => (\n <tr key={`skeleton-${rowIndex}`} className=\"animate-pulse border-t border-border-subtle\" aria-hidden>\n {selectable && (\n <td className={cn(cellClasses, \"h-row-lg\")}>\n <span className=\"block size-4 rounded-xs bg-surface-hover\" />\n </td>\n )}\n {columns.map((column, columnIndex) => (\n <td key={column.id} className={cn(cellClasses, \"h-row-lg\")} style={{ width: column.width }}>\n <span\n className=\"block h-3 rounded-xs bg-surface-hover\"\n // Uneven widths, so a column of placeholders reads as\n // text rather than as a set of progress bars.\n style={{ width: SKELETON_WIDTHS[(rowIndex + columnIndex) % SKELETON_WIDTHS.length] }}\n />\n </td>\n ))}\n {actions.length > 0 && <td className={cn(cellClasses, \"h-row-lg\")} />}\n </tr>\n ))\n : paginatedData.length === 0\n ? (\n <tr>\n <td\n colSpan={\n columns.length +\n (selectable ? 1 : 0) +\n (actions.length > 0 ? 1 : 0)\n }\n className={cn(\n cellClasses,\n \"border-t border-border-subtle py-10 text-center text-text-muted\"\n )}\n >\n {emptyContent || \"No data available\"}\n </td>\n </tr>\n )\n : paginatedData.map((row, index) => {\n const rowKey = getRowKey(row, index);\n const isSelected = selectedRows.some(\n (selectedRow, i) => getRowKey(selectedRow, i) === rowKey\n );\n\n return (\n <tr\n key={rowKey}\n className={cn(\n rowHeights[size],\n // Hairline above every row, including the first: it is\n // what separates the body from the column strip.\n \"border-t border-border-subtle\",\n hoverable && \"transition-colors duration-fast ease-out hover:bg-surface-hover\",\n onRowClick && \"cursor-pointer\",\n isSelected && \"bg-accent-soft\",\n rowClassName?.(row, index)\n )}\n onClick={(e) => {\n e.stopPropagation();\n onRowClick?.(row, index);\n }}\n >\n {/* Selection Cell */}\n {selectable && (\n <td className={cellClasses}>\n <Checkbox\n size=\"sm\"\n checked={isSelected}\n onClick={(e) => e.stopPropagation()}\n onChange={(e) => {\n e.stopPropagation();\n handleRowSelection(row, e.target.checked);\n }}\n aria-label=\"Select row\"\n />\n </td>\n )}\n\n {/* Data Cells */}\n {columns.map((column) => {\n const value =\n typeof column.accessor === \"function\"\n ? column.accessor(row)\n : row[column.accessor];\n\n return (\n <td\n key={column.id}\n className={cn(cellClasses, {\n \"text-left\":\n column.align === \"left\" || !column.align,\n \"text-center\": column.align === \"center\",\n \"text-right\": column.align === \"right\",\n \"sticky left-0 bg-surface\":\n column.sticky === \"left\",\n \"sticky right-0 bg-surface\":\n column.sticky === \"right\",\n })}\n >\n {column.cell\n ? column.cell(value, row, index)\n : String(value || \"\")}\n </td>\n );\n })}\n\n {/* Actions Cell */}\n {actions.length > 0 && (\n <td className={cellClasses}>\n <Dropdown\n className=\"rounded-md\"\n trigger={\n <span className=\"grid size-7 place-items-center text-text-subtle\">\n <Icon icon={Ellipsis} size=\"md\" color=\"current\" />\n </span>\n }\n options={actions.map((action) => ({\n value: action.id,\n label: action.label,\n icon: action.icon,\n disabled: action.disabled?.(row),\n }))}\n onSelect={(actionId) => {\n const action = actions.find(\n (a) => a.id === actionId\n );\n if (action) {\n action.onClick(row, index);\n }\n }}\n placement=\"bottom-end\"\n />\n </td>\n )}\n </tr>\n );\n })}\n </tbody>\n </table>\n </div>\n\n {showFooter && (\n <div className=\"flex flex-wrap items-center gap-3 px-1 pt-3 text-xs text-text-muted\">\n <span className=\"min-w-0 flex-1\">\n {footerSummary ?? `Showing ${startItem}–${endItem} of ${totalItems}`}\n </span>\n\n {showPaginator && <div className=\"flex items-center gap-0.5\">\n <Button\n size=\"xs\"\n variant=\"ghost\"\n iconOnly\n aria-label=\"Previous page\"\n onClick={() => handlePageChange(pagination.page - 1)}\n disabled={pagination.page === 0}\n >\n <Icon icon={ChevronLeft} size=\"md\" color=\"current\" />\n </Button>\n\n {pageWindow(pagination.page, totalPages).map((entry, index) =>\n entry === \"gap\" ? (\n <span key={`gap-${index}`} className=\"px-1 text-text-subtle\">\n …\n </span>\n ) : (\n <button\n key={entry}\n type=\"button\"\n aria-current={entry === pagination.page ? \"page\" : undefined}\n onClick={() => handlePageChange(entry)}\n className={cn(\n \"h-control-xs min-w-6 cursor-pointer rounded-sm px-1.5 tabular-nums\",\n \"transition-colors duration-fast ease-out\",\n \"focus-visible:outline-none focus-visible:focus-ring\",\n entry === pagination.page\n ? \"bg-surface-sunk font-semibold text-text\"\n : \"text-text-muted hover:bg-surface-hover hover:text-text\",\n )}\n >\n {entry + 1}\n </button>\n ),\n )}\n\n <Button\n size=\"xs\"\n variant=\"ghost\"\n iconOnly\n aria-label=\"Next page\"\n onClick={() => handlePageChange(pagination.page + 1)}\n disabled={pagination.page >= totalPages - 1}\n >\n <Icon icon={ChevronRight} size=\"md\" color=\"current\" />\n </Button>\n </div>}\n </div>\n )}\n </div>\n );\n};\n","import React, { createContext, useContext, useState } from 'react';\nimport { cn } from '../utils/cn';\n\nexport interface TabItem {\n /** Tab identifier */\n id: string;\n /** Tab label */\n label: string;\n /** Tab content */\n content?: React.ReactNode;\n /** Whether tab is disabled */\n disabled?: boolean;\n /** Badge/count to show next to label */\n badge?: string | number;\n}\n\nexport interface TabsProps {\n /** Tab items */\n items: TabItem[];\n /** Default active tab */\n defaultTab?: string;\n /** Active tab (controlled) */\n activeTab?: string;\n /** Tab change handler */\n onTabChange?: (tabId: string) => void;\n /** Tabs variant */\n variant?: 'default' | 'pills' | 'underline';\n /** Tabs size */\n size?: 'sm' | 'md' | 'lg';\n /** Additional CSS classes */\n className?: string;\n}\n\nexport interface TabBarProps {\n /** Tab items (simplified for bar style) */\n items: Array<{\n id: string;\n label: string;\n badge?: string | number;\n disabled?: boolean;\n }>;\n /** Active tab */\n activeTab?: string;\n /** Tab change handler */\n onTabChange?: (tabId: string) => void;\n /** Additional CSS classes */\n className?: string;\n}\n\nconst TabsContext = createContext<{\n activeTab: string;\n setActiveTab: (tab: string) => void;\n} | null>(null);\n\n/**\n * TabBar component for simple tab navigation (like in the screenshot)\n */\nexport const TabBar: React.FC<TabBarProps> = ({\n items,\n activeTab,\n onTabChange,\n className,\n}) => {\n const [internalActiveTab, setInternalActiveTab] = useState(items[0]?.id || '');\n const currentActiveTab = activeTab || internalActiveTab;\n\n const handleTabClick = (tabId: string) => {\n if (onTabChange) {\n onTabChange(tabId);\n } else {\n setInternalActiveTab(tabId);\n }\n };\n\n return (\n <div className={cn('border-b border-border', className)}>\n <nav className=\"-mb-px flex space-x-8\">\n {items.map((item) => (\n <button\n key={item.id}\n onClick={() => !item.disabled && handleTabClick(item.id)}\n disabled={item.disabled}\n className={cn(\n 'border-b-2 py-2 px-1 text-sm font-medium transition-colors duration-fast',\n {\n 'border-accent-border text-text': currentActiveTab === item.id,\n 'border-transparent text-text-muted hover:text-text':\n currentActiveTab !== item.id && !item.disabled,\n 'border-transparent text-text-disabled cursor-not-allowed': item.disabled,\n }\n )}\n >\n <span className=\"flex items-center gap-2\">\n {item.label}\n {item.badge && (\n <span className={cn(\n 'inline-flex items-center px-2 py-0.5 rounded-full text-xs font-medium',\n currentActiveTab === item.id\n ? 'bg-accent-soft text-accent'\n : 'bg-surface-hover text-text-muted'\n )}>\n {item.badge}\n </span>\n )}\n </span>\n </button>\n ))}\n </nav>\n </div>\n );\n};\n\n/**\n * Full Tabs component with content panels\n */\nexport const Tabs: React.FC<TabsProps> = ({\n items,\n defaultTab,\n activeTab,\n onTabChange,\n variant = 'default',\n size = 'md',\n className,\n}) => {\n const [internalActiveTab, setInternalActiveTab] = useState(\n defaultTab || activeTab || items[0]?.id || ''\n );\n\n const currentActiveTab = activeTab || internalActiveTab;\n\n const handleTabChange = (tabId: string) => {\n if (onTabChange) {\n onTabChange(tabId);\n } else {\n setInternalActiveTab(tabId);\n }\n };\n\n const contextValue = {\n activeTab: currentActiveTab,\n setActiveTab: handleTabChange,\n };\n\n const activeTabItem = items.find(item => item.id === currentActiveTab);\n\n const tabListClasses = cn(\n 'flex',\n {\n 'border-b border-border px-2': variant === 'default' || variant === 'underline',\n 'bg-surface-hover p-1 rounded-lg': variant === 'pills',\n 'space-x-1': variant === 'pills',\n 'space-x-8': variant === 'default' || variant === 'underline',\n },\n className\n );\n\n const tabClasses = (item: TabItem, isActive: boolean) => {\n const baseClasses = 'transition-colors duration-fast font-medium';\n\n const sizeClasses = {\n 'text-xs px-2 py-1': size === 'sm',\n 'text-sm px-3 py-2': size === 'md',\n 'text-base px-4 py-3': size === 'lg',\n };\n\n const variantClasses = {\n // Default variant\n 'border-b-2 -mb-px': variant === 'default',\n // Pills variant\n 'rounded-md': variant === 'pills',\n // Underline variant\n 'border-b-2 pb-2': variant === 'underline',\n };\n\n const stateClasses = {\n 'opacity-50 cursor-not-allowed': item.disabled,\n 'cursor-pointer': !item.disabled,\n };\n\n // Active state classes\n const activeClasses = isActive ? {\n 'border-accent-border text-text': variant === 'default' || variant === 'underline',\n 'bg-surface text-text shadow-none': variant === 'pills',\n } : {};\n\n // Non-active, non-disabled state classes\n const inactiveClasses = !isActive && !item.disabled ? {\n 'border-transparent text-text-muted hover:text-text': variant === 'default',\n 'text-text-muted hover:text-text': variant === 'pills',\n 'border-transparent text-text-muted hover:text-text hover:border-border': variant === 'underline',\n } : {};\n\n return cn(baseClasses, sizeClasses, variantClasses, stateClasses, activeClasses, inactiveClasses);\n };\n\n return (\n <TabsContext.Provider value={contextValue}>\n <div>\n {/* Tab List */}\n <div className={tabListClasses} role=\"tablist\">\n {items.map((item) => (\n <button\n key={item.id}\n type=\"button\"\n role=\"tab\"\n aria-selected={currentActiveTab === item.id}\n aria-controls={`tabpanel-${item.id}`}\n disabled={item.disabled}\n onClick={() => !item.disabled && handleTabChange(item.id)}\n className={tabClasses(item, currentActiveTab === item.id)}\n >\n <span className=\"flex items-center gap-2\">\n {item.label}\n {item.badge && (\n <span className=\"inline-flex items-center px-2 py-0.5 rounded-full text-xs font-medium bg-surface-hover text-text-muted\">\n {item.badge}\n </span>\n )}\n </span>\n </button>\n ))}\n </div>\n\n {/* Tab Content */}\n {activeTabItem?.content && (\n <div\n role=\"tabpanel\"\n id={`tabpanel-${currentActiveTab}`}\n aria-labelledby={`tab-${currentActiveTab}`}\n className=\"mt-4\"\n >\n {activeTabItem.content}\n </div>\n )}\n </div>\n </TabsContext.Provider>\n );\n};\n\n/**\n * Hook to access tab context\n */\nexport const useTabsContext = () => {\n const context = useContext(TabsContext);\n if (!context) {\n throw new Error('useTabsContext must be used within a Tabs component');\n }\n return context;\n}; ","import React, { useEffect, useRef } from 'react';\nimport { X } from \"lucide-react\";\nimport { Icon } from \"../content/Icon\";\nimport { cn } from '../utils/cn';\n\nexport interface ModalProps {\n /**\n * Whether the modal is open\n */\n open: boolean;\n \n /**\n * Callback fired when the modal should be closed\n */\n onClose: () => void;\n \n /**\n * The title of the modal\n */\n title?: string;\n \n /**\n * The size of the modal\n */\n size?: 'sm' | 'md' | 'lg' | 'xl' | 'full';\n \n /**\n * Whether clicking the backdrop should close the modal\n */\n closeOnBackdropClick?: boolean;\n \n /**\n * Whether pressing escape should close the modal\n */\n closeOnEscape?: boolean;\n \n /**\n * Additional class name for the modal content\n */\n className?: string;\n \n /**\n * Additional class name for the modal backdrop\n */\n backdropClassName?: string;\n \n /**\n * The content of the modal\n */\n children: React.ReactNode;\n \n /**\n * Footer content for the modal\n */\n footer?: React.ReactNode;\n \n /**\n * Whether to show the close button\n */\n showCloseButton?: boolean;\n}\n\nconst modalSizes = {\n sm: 'max-w-md',\n md: 'max-w-lg',\n lg: 'max-w-2xl',\n xl: 'max-w-4xl',\n full: 'max-w-full mx-4',\n};\n\n/**\n * Modal component with theme integration and accessibility features\n * \n * @example\n * ```tsx\n * <Modal\n * open={isOpen}\n * onClose={() => setIsOpen(false)}\n * title=\"Confirm Action\"\n * size=\"md\"\n * >\n * <p>Are you sure you want to delete this item?</p>\n * </Modal>\n * \n * <Modal\n * open={isOpen}\n * onClose={() => setIsOpen(false)}\n * title=\"Settings\"\n * size=\"lg\"\n * footer={\n * <div className=\"flex justify-end space-x-2\">\n * <Button variant=\"outline\" onClick={() => setIsOpen(false)}>\n * Cancel\n * </Button>\n * <Button onClick={handleSave}>\n * Save\n * </Button>\n * </div>\n * }\n * >\n * <SettingsForm />\n * </Modal>\n * ```\n */\nexport function Modal({\n open,\n onClose,\n title,\n size = 'md',\n closeOnBackdropClick = true,\n closeOnEscape = true,\n className,\n backdropClassName,\n children,\n footer,\n showCloseButton = true,\n}: ModalProps) {\n const modalRef = useRef<HTMLDivElement>(null);\n const previousActiveElement = useRef<HTMLElement | null>(null);\n\n // Handle escape key\n useEffect(() => {\n if (!open || !closeOnEscape) return;\n\n const handleEscape = (event: KeyboardEvent) => {\n if (event.key === 'Escape') {\n onClose();\n }\n };\n\n document.addEventListener('keydown', handleEscape);\n return () => document.removeEventListener('keydown', handleEscape);\n }, [open, closeOnEscape, onClose]);\n\n // Handle focus management\n useEffect(() => {\n if (open) {\n // Store the currently focused element\n previousActiveElement.current = document.activeElement as HTMLElement;\n \n // Focus the modal\n if (modalRef.current) {\n modalRef.current.focus();\n }\n \n // Prevent body scroll\n document.body.style.overflow = 'hidden';\n } else {\n // Restore focus to the previously focused element\n if (previousActiveElement.current) {\n previousActiveElement.current.focus();\n }\n \n // Restore body scroll\n document.body.style.overflow = '';\n }\n\n return () => {\n document.body.style.overflow = '';\n };\n }, [open]);\n\n // Handle backdrop click\n const handleBackdropClick = (event: React.MouseEvent) => {\n if (closeOnBackdropClick && event.target === event.currentTarget) {\n onClose();\n }\n };\n\n if (!open) return null;\n\n return (\n <div\n className={cn(\n 'fixed inset-0 z-modal flex items-center justify-center p-4',\n 'bg-scrim',\n // 'animate-fade-in',\n backdropClassName\n )}\n onClick={handleBackdropClick}\n >\n <div\n ref={modalRef}\n className={cn(\n 'relative w-full bg-surface rounded-lg shadow-modal',\n // 'animate-scale-in',\n 'focus:outline-none',\n modalSizes[size],\n className\n )}\n role=\"dialog\"\n aria-modal=\"true\"\n aria-labelledby={title ? 'modal-title' : undefined}\n tabIndex={-1}\n >\n {/* Header */}\n {(title || showCloseButton) && (\n <div className=\"flex items-center justify-between p-6 pb-0\">\n {title && (\n <span\n id=\"modal-title\"\n className=\"text-lg font-semibold text-text\"\n >\n {title}\n </span>\n )}\n \n {showCloseButton && (\n <button\n onClick={onClose}\n className=\"p-1 text-text-muted hover:text-text transition-colors\"\n aria-label=\"Close modal\"\n >\n <Icon icon={X} size=\"lg\" color=\"current\" />\n </button>\n )}\n </div>\n )}\n\n {/* Content */}\n <div className=\"p-6\">\n {children}\n </div>\n\n {/* Footer */}\n {footer && (\n <div className=\"px-6 py-4\">\n {footer}\n </div>\n )}\n </div>\n </div>\n );\n} ","import { FilePointer, VirtualMount } from '@opencxh/domain';\nimport { ArrowLeft, FileText, Folder, FolderPlus, HardDrive, Search, Upload, X } from 'lucide-react';\nimport React, { useEffect, useMemo, useRef, useState } from 'react';\nimport { Button } from '../action/Button';\nimport { Icon } from '../content/Icon';\nimport { Table, TableColumn } from '../content/Table';\nimport { Tabs } from '../navigation/Tabs';\nimport { Modal } from '../overlays/Modal';\nimport { Text } from '../typography/Text';\nimport { cn } from '../utils/cn';\nimport { TextField } from './TextField';\n\nexport interface StorageInputProps {\n value?: string | FilePointer;\n onChange: (value: FilePointer | null, content?: Uint8Array) => void;\n label?: string;\n placeholder?: string;\n error?: string;\n disabled?: boolean;\n accept?: string;\n onListFiles?: (filters?: { name?: string; mimeType?: string; mountId?: string, path?: string }) => Promise<{ data: FilePointer[] }> | undefined;\n onListMounts?: () => Promise<{ data: VirtualMount[] }> | undefined;\n onUploadFile?: (payload: { file: Uint8Array; filename: string; mimeType: string; mountId?: string; path?: string }) => Promise<{ data: FilePointer }> | undefined;\n onDownloadFile?: (fileId: string) => Promise<Uint8Array> | undefined;\n onRegisterFile?: (payload: Omit<FilePointer, 'id'>) => Promise<{ data: FilePointer }> | undefined;\n}\n\nexport const StorageInput: React.FC<StorageInputProps> = ({\n value,\n onChange,\n label,\n placeholder = \"Select or upload a file\",\n error,\n disabled,\n accept,\n onListFiles,\n onListMounts,\n onUploadFile,\n onDownloadFile,\n onRegisterFile,\n}) => {\n const [isModalOpen, setIsModalOpen] = useState(false);\n const [mounts, setMounts] = useState<VirtualMount[]>([]);\n const [selectedMount, setSelectedMount] = useState<VirtualMount | null>(null);\n const [currentPath, setCurrentPath] = useState<string>(\"/\");\n const [remoteFiles, setRemoteFiles] = useState<FilePointer[]>([]);\n const [loading, setLoading] = useState(false);\n const [searchTerm, setSearchTerm] = useState(\"\");\n const [selectedPointer, setSelectedPointer] = useState<FilePointer | null>(\n typeof value === 'object' ? value : null\n );\n const [isCreatingFolder, setIsCreatingFolder] = useState(false);\n const [newFolderName, setNewFolderName] = useState(\"\");\n\n const fileInputRef = useRef<HTMLInputElement>(null);\n\n // Load mounts when modal opens\n useEffect(() => {\n if (isModalOpen) {\n loadMounts();\n }\n }, [isModalOpen]);\n\n // Load files when a mount is selected or search term changes\n useEffect(() => {\n if (isModalOpen && selectedMount) {\n loadFiles();\n }\n }, [isModalOpen, selectedMount, currentPath, searchTerm]);\n\n const loadMounts = async () => {\n setLoading(true);\n try {\n const resp = await onListMounts?.();\n if (resp?.data) {\n setMounts(resp.data);\n }\n } catch (err) {\n console.error(\"Failed to load mounts\", err);\n } finally {\n setLoading(false);\n }\n };\n\n const loadFiles = async () => {\n if (!selectedMount) return;\n setLoading(true);\n try {\n const resp = await onListFiles?.({ mountId: selectedMount.id, name: searchTerm, path: currentPath });\n if (resp?.data) {\n setRemoteFiles(resp.data);\n }\n } catch (err) {\n console.error(\"Failed to load files\", err);\n } finally {\n setLoading(false);\n }\n };\n\n const handleLocalOnlySelection = async (e: React.ChangeEvent<HTMLInputElement>) => {\n const file = e.target.files?.[0];\n if (!file) return;\n\n setLoading(true);\n try {\n const buffer = await file.arrayBuffer();\n const content = new Uint8Array(buffer);\n\n const virtualPointer: FilePointer = {\n id: `local-${Date.now()}`,\n name: file.name,\n type: 'file',\n path: '/',\n mimeType: file.type || 'application/octet-stream',\n size: file.size,\n mountId: 'local',\n providerKey: file.name,\n ownerId: 'me',\n };\n\n setSelectedPointer(virtualPointer);\n onChange(virtualPointer, content);\n setIsModalOpen(false);\n } catch (err) {\n console.error(\"Local file selection failed\", err);\n } finally {\n setLoading(false);\n }\n };\n\n const handleUploadToStorage = async (e: React.ChangeEvent<HTMLInputElement>) => {\n const file = e.target.files?.[0];\n if (!file || !selectedMount) return;\n\n setLoading(true);\n try {\n const buffer = await file.arrayBuffer();\n const resp = await onUploadFile?.({\n file: new Uint8Array(buffer),\n filename: file.name,\n mimeType: file.type || 'application/octet-stream',\n mountId: selectedMount.id,\n path: currentPath,\n });\n\n if (resp?.data) {\n const pointer = resp.data;\n setSelectedPointer(pointer);\n onChange(pointer, new Uint8Array(buffer));\n setIsModalOpen(false);\n }\n } catch (err) {\n console.error(\"Upload failed\", err);\n } finally {\n setLoading(false);\n }\n };\n\n const handleCreateFolder = async () => {\n if (!newFolderName || !selectedMount) return;\n\n setLoading(true);\n try {\n const fullPath = `${currentPath}${newFolderName}/`;\n\n if (onRegisterFile) {\n await onRegisterFile({\n name: newFolderName,\n type: 'folder',\n path: currentPath,\n mimeType: 'application/x-directory',\n size: 0,\n mountId: selectedMount.id,\n providerKey: fullPath,\n ownerId: 'me',\n });\n await loadFiles();\n }\n\n setIsCreatingFolder(false);\n setNewFolderName(\"\");\n } catch (err) {\n console.error(\"Failed to create folder\", err);\n } finally {\n setLoading(false);\n }\n };\n\n const handleSelectRemote = async (pointer: FilePointer) => {\n setLoading(true);\n try {\n const content = await onDownloadFile?.(pointer.id);\n setSelectedPointer(pointer);\n onChange(pointer, content);\n setIsModalOpen(false);\n } catch (err) {\n console.error(\"Failed to download file\", err);\n } finally {\n setLoading(false);\n }\n };\n\n const handleClear = (e: React.MouseEvent) => {\n e.stopPropagation();\n setSelectedPointer(null);\n onChange(null);\n };\n\n // Folder & File calculation logic\n const explorerItems = useMemo(() => {\n const folders = new Set<string>();\n const files: FilePointer[] = [];\n\n remoteFiles.forEach(file => {\n if (file.type === 'folder') {\n if (file.path === currentPath) {\n folders.add(file.name);\n }\n return;\n }\n\n const path = file.providerKey || file.name;\n const relativePath = currentPath ? path.substring(currentPath.length) : path;\n const parts = relativePath.split('/').filter(p => p !== \"\");\n\n if (parts.length > 1) {\n folders.add(parts[0]);\n } else if (parts.length === 1) {\n files.push(file);\n }\n });\n\n return {\n folders: Array.from(folders).sort(),\n files: files.sort((a, b) => a.name.localeCompare(b.name))\n };\n }, [remoteFiles, currentPath]);\n\n const handleFolderClick = (folderName: string) => {\n setCurrentPath(prev => `${prev}${folderName}/`);\n };\n\n const handleGoBack = () => {\n const parts = currentPath.split('/').filter(p => p !== \"\");\n parts.pop();\n if (parts.length === 0) {\n setCurrentPath(\"/\");\n } else {\n setCurrentPath(`${parts.join('/')}/`);\n }\n };\n\n const tableData = useMemo(() => {\n const data: any[] = explorerItems.folders.map(f => ({\n id: `folder-${f}`,\n name: f,\n type: 'folder'\n }));\n\n explorerItems.files.forEach(f => {\n data.push({\n ...f,\n type: 'file'\n });\n });\n\n return data;\n }, [explorerItems]);\n\n const explorerColumns: TableColumn<any>[] = [\n {\n id: 'name',\n header: 'Name',\n accessor: 'name',\n cell: (val, row) => (\n <div className=\"flex items-center gap-2\">\n <Icon\n icon={row.type === 'folder' ? Folder : FileText}\n size=\"sm\"\n color={row.type === 'folder' ? \"warning\" : \"secondary\"}\n />\n <span className={cn(row.type === 'folder' && \"font-medium\")}>{val}</span>\n </div>\n )\n },\n {\n id: 'type',\n header: 'Type',\n accessor: (row) => row.type === 'folder' ? 'Folder' : row.mimeType,\n },\n {\n id: 'size',\n header: 'Size',\n accessor: (row) => row.type === 'file' ? `${(row.size / 1024).toFixed(1)} KB` : '-',\n },\n {\n id: 'actions',\n header: '',\n accessor: 'id',\n align: 'right',\n cell: (_, row) => (\n <Button\n variant=\"outline\"\n onClick={(e) => {\n e.stopPropagation();\n row.type === 'folder' ? handleFolderClick(row.name) : handleSelectRemote(row);\n }}\n loading={loading && row.type === 'file' && selectedPointer?.id === row.id}\n >\n {row.type === 'folder' ? 'Open' : 'Select'}\n </Button>\n )\n }\n ];\n\n const mountColumns: TableColumn<VirtualMount>[] = [\n {\n id: 'name',\n header: 'Mount Name',\n accessor: 'name',\n cell: (val) => (\n <div className=\"flex items-center gap-2 font-medium\">\n <Icon icon={HardDrive} size=\"sm\" color=\"primary\" />\n <span>{val}</span>\n </div>\n )\n },\n {\n id: 'actions',\n header: '',\n accessor: 'id',\n align: 'right',\n cell: (_, row) => (\n <Button variant=\"outline\" onClick={() => setSelectedMount(row)}>\n Open\n </Button>\n )\n }\n ];\n\n return (\n <div className=\"space-y-1\">\n {label && (\n <Text variant=\"label\" size=\"sm\" weight=\"medium\">\n {label}\n </Text>\n )}\n\n <div\n onClick={() => !disabled && setIsModalOpen(true)}\n className={cn(\n \"flex items-center gap-3 px-3 py-2 border rounded-lg cursor-pointer transition-colors\",\n \"hover:border-border-strong bg-surface\",\n error ? \"border-danger-border\" : \"border-border\",\n disabled && \"opacity-50 cursor-not-allowed bg-surface-sunk\"\n )}\n >\n <div className=\"flex-shrink-0\">\n <Icon icon={selectedPointer ? FileText : HardDrive} color={selectedPointer ? \"primary\" : \"secondary\"} />\n </div>\n\n <div className=\"flex-grow truncate\">\n {selectedPointer ? (\n <span className=\"text-sm text-text font-medium\">{selectedPointer.name}</span>\n ) : (\n <span className=\"text-sm text-text-muted\">{placeholder}</span>\n )}\n </div>\n\n {selectedPointer && !disabled && (\n <button\n onClick={handleClear}\n className=\"p-1 hover:bg-surface-hover rounded\"\n >\n <Icon icon={X} size=\"xs\" />\n </button>\n )}\n </div>\n\n {error && (\n <Text variant=\"body\" size=\"xs\" className=\"text-danger-fg\">\n {error}\n </Text>\n )}\n\n <Modal\n open={isModalOpen}\n onClose={() => {\n setIsModalOpen(false);\n setSelectedMount(null);\n setCurrentPath(\"/\");\n setIsCreatingFolder(false);\n }}\n title={selectedMount ? `Explorer: ${selectedMount.name}` : \"Select Storage Mount\"}\n size=\"lg\"\n >\n <Tabs\n variant=\"pills\"\n items={[\n {\n id: 'remote',\n label: 'Platform Storage',\n content: (\n <div className=\"space-y-4\">\n {selectedMount ? (\n <>\n <div className=\"flex flex-wrap items-center gap-2\">\n <Button\n variant=\"ghost\"\n onClick={() => {\n if (currentPath && currentPath !== \"/\") {\n handleGoBack();\n } else {\n setSelectedMount(null);\n }\n }}\n leftIcon={<Icon icon={ArrowLeft} size=\"xs\" />}\n >\n {currentPath ? \"Back\" : \"Back to Mounts\"}\n </Button>\n\n <div className=\"flex items-center gap-1 text-xs text-text-muted overflow-hidden bg-surface-hover px-2 py-1 rounded\">\n <span className=\"truncate\">{currentPath}</span>\n </div>\n\n <div className=\"flex-grow min-w-40\">\n <TextField\n placeholder=\"Search...\"\n value={searchTerm}\n onChange={(e) => setSearchTerm(e.target.value)}\n startIcon={<Search size={14} />}\n fullWidth\n />\n </div>\n\n <div className=\"flex items-center gap-1\">\n <Button\n variant=\"outline\"\n onClick={() => setIsCreatingFolder(true)}\n leftIcon={<Icon icon={FolderPlus} size=\"xs\" />}\n >\n New Folder\n </Button>\n <Button\n variant=\"primary\"\n onClick={() => fileInputRef.current?.click()}\n leftIcon={<Icon icon={Upload} size=\"xs\" />}\n loading={loading}\n >\n Upload\n </Button>\n <input\n type=\"file\"\n className=\"hidden\"\n ref={fileInputRef}\n onChange={handleUploadToStorage}\n accept={accept}\n />\n </div>\n </div>\n\n {isCreatingFolder && (\n <div className=\"flex items-center gap-2 p-3 bg-surface-sunk rounded-lg border border-border\">\n <Icon icon={Folder} size=\"sm\" color=\"warning\" />\n <TextField\n placeholder=\"Folder name\"\n value={newFolderName}\n onChange={(e) => setNewFolderName(e.target.value)}\n autoFocus\n />\n <Button onClick={handleCreateFolder} loading={loading}>Create</Button>\n <Button variant=\"ghost\" onClick={() => setIsCreatingFolder(false)}>Cancel</Button>\n </div>\n )}\n\n <div className=\"max-h-100 overflow-auto rounded-lg border border-border\">\n <Table\n data={tableData}\n columns={explorerColumns}\n loading={loading}\n emptyContent=\"This folder is empty\"\n onRowClick={(row) => row.type === 'folder' ? handleFolderClick(row.name) : handleSelectRemote(row)}\n />\n </div>\n </>\n ) : (\n <div className=\"max-h-100 overflow-auto rounded-lg border border-border\">\n <Table\n data={mounts}\n columns={mountColumns}\n loading={loading}\n emptyContent=\"No storage mounts configured\"\n onRowClick={(row) => setSelectedMount(row)}\n />\n </div>\n )}\n </div>\n )\n },\n {\n id: 'local',\n label: 'Local File',\n content: (\n <div className=\"space-y-6\">\n <div className=\"flex flex-col items-center justify-center py-12 border-2 border-dashed border-border rounded-xl bg-surface-sunk/50\">\n <div className=\"p-4 bg-accent-soft rounded-full mb-4\">\n <Icon icon={FileText} size=\"xl\" color=\"primary\" />\n </div>\n <Text variant=\"label\" size=\"lg\" weight=\"semibold\">\n Select a file from your computer\n </Text>\n <Text variant=\"body\" size=\"sm\" className=\"text-text-muted mt-1 mb-6 text-center max-w-xs\">\n This file will be used directly in the form and will <strong>not</strong> be uploaded to platform storage.\n </Text>\n\n <label className=\"cursor-pointer\">\n <Button variant=\"primary\" size=\"lg\" loading={loading} className=\"pointer-events-none\">\n Browse Local File\n </Button>\n <input\n type=\"file\"\n className=\"hidden\"\n onChange={handleLocalOnlySelection}\n accept={accept}\n disabled={loading}\n />\n </label>\n </div>\n </div>\n )\n }\n ]}\n />\n </Modal>\n </div>\n );\n};\n","import React, { forwardRef } from 'react';\nimport { cn } from '../utils/cn';\nimport { fieldEdgeClasses, fieldFrameClasses, fieldLabelClasses } from './TextField';\n\nexport interface TextAreaProps extends Omit<React.TextareaHTMLAttributes<HTMLTextAreaElement>, 'size'> {\n /**\n * The label for the textarea field\n */\n label?: string;\n\n /**\n * Helper text to display below the textarea\n */\n helperText?: string;\n\n /**\n * Error message to display when the textarea is invalid\n */\n error?: string;\n\n /**\n * The size of the textarea field\n */\n size?: 'sm' | 'md' | 'lg' | 'full';\n\n /**\n * Whether the textarea should take the full width of its container\n */\n fullWidth?: boolean;\n\n /**\n * Whether the textarea is in a loading state\n */\n loading?: boolean;\n\n /**\n * Additional class name for the container\n */\n containerClassName?: string;\n\n /**\n * Additional class name for the label\n */\n labelClassName?: string;\n}\n\nconst textareaSizes = {\n sm: 'px-3 py-1.5 text-sm',\n md: 'px-3 py-2 text-base',\n lg: 'px-3 py-2 text-md',\n full: 'px-3 py-2 text-md',\n};\n\n/**\n * TextArea component with theme integration and validation states\n */\nexport const TextArea = forwardRef<HTMLTextAreaElement, TextAreaProps>(\n (\n {\n label,\n helperText,\n error,\n size = 'md',\n fullWidth = false,\n loading = false,\n containerClassName,\n labelClassName,\n className,\n id,\n rows = 4,\n ...props\n },\n ref\n ) => {\n const reactId = React.useId();\n const textareaId = id || `textarea-${reactId}`;\n const hasError = Boolean(error);\n const describedBy = error || helperText ? `${textareaId}-description` : undefined;\n\n return (\n <div className={cn('flex flex-col', fullWidth && 'w-full', containerClassName)}>\n {label && (\n <label\n htmlFor={textareaId}\n className={cn(\n fieldLabelClasses,\n hasError ? 'text-danger-fg' : 'text-text-muted',\n labelClassName\n )}\n >\n {label}\n </label>\n )}\n\n <div className=\"relative\">\n <textarea\n ref={ref}\n id={textareaId}\n rows={rows}\n aria-invalid={hasError || undefined}\n aria-describedby={describedBy}\n className={cn(\n fieldFrameClasses,\n 'resize-y leading-relaxed',\n\n textareaSizes[size],\n\n fieldEdgeClasses(hasError),\n\n className\n )}\n {...props}\n />\n\n {loading && (\n <span\n aria-hidden\n className=\"absolute top-2 right-3 size-icon-md animate-spin rounded-full border-2 border-border border-t-transparent\"\n />\n )}\n </div>\n\n {(error || helperText) && (\n <p\n id={describedBy}\n className={cn('mt-1 text-xs', hasError ? 'text-danger-fg' : 'text-text-subtle')}\n >\n {error || helperText}\n </p>\n )}\n </div>\n );\n }\n);\n\nTextArea.displayName = 'TextArea';\n","/**\n * Keeping password managers out of fields that are not credentials.\n *\n * The problem was not that autofill was switched on — it was that most fields\n * asked for it by accident. A form field passed things like `\"sip-password\"`,\n * `\"api-key\"`, `\"record-pin\"` or `\"system-prompt\"` as its autocomplete value.\n * None of those are autocomplete tokens, and the HTML spec says an unrecognised\n * token behaves as `on`. So the fields most likely to be mistaken for a login\n * were the ones most loudly inviting Bitwarden, LastPass and Dashlane to fill\n * them in — and to offer to save them.\n *\n * `autocomplete=\"off\"` alone does not settle it: the major managers ignore it on\n * purpose, because sites used to abuse it. Each honours its own opt-out\n * attribute instead, so a field that means it has to say so in four dialects.\n */\n\n/**\n * The autocomplete tokens we actually want honoured. Anything outside this set\n * is treated as \"someone wrote a note to themselves in this field\", not as a\n * browser instruction.\n */\nconst REAL_TOKENS = new Set([\n \"name\", \"given-name\", \"family-name\", \"additional-name\", \"nickname\",\n \"honorific-prefix\", \"honorific-suffix\",\n \"email\", \"username\", \"organization\", \"organization-title\",\n \"tel\", \"tel-country-code\", \"tel-national\", \"tel-extension\",\n \"url\", \"photo\", \"language\", \"bday\", \"sex\",\n \"street-address\", \"address-line1\", \"address-line2\", \"address-line3\",\n \"address-level1\", \"address-level2\", \"country\", \"country-name\", \"postal-code\",\n \"current-password\", \"new-password\", \"one-time-code\",\n]);\n\nexport interface AutofillProps {\n autoComplete: string;\n \"data-1p-ignore\"?: string;\n \"data-lpignore\"?: string;\n \"data-bwignore\"?: string;\n \"data-form-type\"?: string;\n}\n\n/**\n * Props that switch a field's autofill behaviour on or off deliberately.\n *\n * Pass the field's declared autocomplete value; a genuine token is honoured, and\n * anything else — including nothing at all — turns autofill off and tells each\n * manager so in the attribute it listens to.\n */\nexport function autofillProps(token?: string): AutofillProps {\n if (token && REAL_TOKENS.has(token)) return { autoComplete: token };\n\n return {\n autoComplete: \"off\",\n // 1Password\n \"data-1p-ignore\": \"true\",\n // LastPass\n \"data-lpignore\": \"true\",\n // Bitwarden\n \"data-bwignore\": \"true\",\n // Dashlane — \"other\" means \"not a login field\".\n \"data-form-type\": \"other\",\n };\n}\n","import { FilePointer, InternalSDK, VirtualMount } from \"@opencxh/domain\";\nimport { Plus, Trash2 } from \"lucide-react\";\nimport React, { useCallback, useEffect, useState } from \"react\";\nimport { Button } from \"../action/Button\";\nimport { SegmentedToggle } from \"../action/SegmentedToggle\";\nimport { Checkbox } from \"../input/Checkbox\";\nimport { DatePicker } from \"../input/DatePicker\";\nimport { FolderSelect, type FolderDestination } from \"../input/FolderSelect\";\nimport { Select } from \"../input/Select\";\nimport { StorageInput } from \"../input/StorageInput\";\nimport { TextArea } from \"../input/TextArea\";\nimport { TextField } from \"../input/TextField\";\nimport { cn } from \"../utils/cn\";\nimport { autofillProps } from \"./autofill\";\n\nexport type FormFieldType =\n | \"text\"\n | \"email\"\n | \"password\"\n | \"number\"\n | \"tel\"\n | \"url\"\n // A colour swatch. Its own type rather than `fieldProps: { type: \"color\" }`,\n // because the `type` prop is applied after the spread and would win.\n | \"color\"\n | \"textarea\"\n | \"select\"\n | \"segmented\"\n | \"checkbox\"\n | \"radio\"\n | \"date\"\n | \"file\"\n | \"folder\"\n | \"custom\"\n | \"array\";\n\n/**\n * `NonNullable` before the `object` test is load-bearing: form data is routinely\n * a `Partial<T>`, which makes every property `X | undefined`, and\n * `Address | undefined extends object` is false -- so without it every nested\n * path silently disappears and only top-level keys survive.\n *\n * Arrays, Dates and functions are treated as leaves. Recursing into them would\n * spell out every index and prototype method, and the resulting union is exactly\n * the kind of size at which TypeScript gives up (see {@link FieldPath}).\n *\n * `T extends unknown ?` makes this distribute over unions. Without it a\n * discriminated union like `OwnerScope` only contributes the keys its members\n * share (`keyof (A | B)` is an intersection), so `ownerScope.teamId` is\n * unspellable even though a `kind: \"team\"` conditional field needs exactly that.\n */\ntype NestedKeys<T> = T extends unknown\n ? {\n [K in keyof T]-?: NonNullable<T[K]> extends\n | readonly unknown[]\n | Date\n | ((...args: never[]) => unknown)\n ? K & string\n : NonNullable<T[K]> extends object\n ? `${K & string}.${NestedKeys<NonNullable<T[K]>>}`\n : K & string;\n }[keyof T]\n : never;\n\n/**\n * What a field may be named: any leaf path, plus any top-level key.\n *\n * The second half matters for `type: \"custom\"` fields, which own a whole\n * sub-object -- a discriminated union, a repeatable list -- and would otherwise\n * be unspellable, since `NestedKeys` only reaches leaves. It is added as a\n * separate union rather than folded into `NestedKeys` itself: doing it inside\n * the recursion doubles the union at every level, and TypeScript quietly gives\n * up on inferring `group.items` once it gets large enough.\n */\ntype FieldPath<T> = NestedKeys<T> | (keyof T & string);\n\nfunction getValueByPath<T>(obj: T, path: string): unknown {\n return path\n .split(\".\")\n .reduce(\n (acc, key) =>\n acc && typeof acc === \"object\" && key in acc\n ? (acc as any)[key]\n : undefined,\n obj\n );\n}\n\nfunction setValueByPath<T extends object>(obj: T, path: string, value: any): T {\n const keys = path.split(\".\");\n const clone: any = Array.isArray(obj)\n ? [...(obj as any)]\n : { ...(obj as any) };\n let cur: any = clone;\n\n for (let i = 0; i < keys.length - 1; i++) {\n const k = keys[i];\n const prev = cur[k];\n cur[k] =\n prev && typeof prev === \"object\"\n ? Array.isArray(prev)\n ? [...prev]\n : { ...prev }\n : {};\n cur = cur[k];\n }\n cur[keys[keys.length - 1]] = value;\n return clone;\n}\n\nfunction unsetByPath<T extends object>(obj: T, path: string): T {\n const keys = path.split(\".\");\n const clone: any = Array.isArray(obj)\n ? [...(obj as any)]\n : { ...(obj as any) };\n let cur: any = clone;\n\n for (let i = 0; i < keys.length - 1; i++) {\n const k = keys[i];\n if (!cur[k] || typeof cur[k] !== \"object\") return clone; // niets te doen\n cur[k] = Array.isArray(cur[k]) ? [...cur[k]] : { ...cur[k] };\n cur = cur[k];\n }\n delete cur[keys[keys.length - 1]];\n return clone;\n}\n\n/**\n * One band of a page-wide form: a fixed label column with the section title and\n * its explanation, and the fields beside it.\n *\n * Exported because a page often has a section that is not a `Form` field at all\n * — a checklist, a list of linked records — and it has to line up with the bands\n * above it. Without this those sections each re-derive the column width and the\n * spacing, and they drift.\n */\nexport function FormSection({\n title,\n description,\n className,\n children,\n}: {\n title?: string;\n description?: string;\n /** Caller owns the divider: only it knows whether it is the last band. */\n className?: string;\n children: React.ReactNode;\n}) {\n return (\n <div className={cn(\"flex flex-col gap-4 py-6 sm:flex-row sm:gap-8\", className)}>\n <div className=\"w-full shrink-0 sm:w-form-label\">\n {title && <span className=\"text-base font-semibold text-text\">{title}</span>}\n {description && (\n <p className=\"mt-1 text-sm leading-relaxed text-pretty text-text-subtle\">\n {description}\n </p>\n )}\n </div>\n <div className=\"min-w-0 flex-1\">{children}</div>\n </div>\n );\n}\n\nexport interface FormGroupItem<T = any> {\n /** Field name (key in form data) */\n name: FieldPath<T>;\n /** Field label */\n label: string;\n /** Field type */\n type: FormFieldType;\n /** Text input type (when type is 'text') */\n textType?: \"text\" | \"email\" | \"password\" | \"number\" | \"tel\" | \"url\";\n /** Field width (CSS width value or grid columns) */\n width?: string | number;\n /** Placeholder text */\n placeholder?: string;\n /**\n * Visible rows for `textarea`. Defaults to 4, which is right for a note and\n * far too small for a field that holds an instruction someone actually reads\n * back while editing (a system prompt).\n */\n rows?: number;\n /**\n * Autocomplete token. Only real HTML tokens (`email`, `tel`, `name`, …) are\n * passed to the browser; anything else switches autofill *off* rather than\n * silently meaning \"on\" — see {@link autofillProps}.\n */\n autocomplete?: string;\n /** Options for select/radio/checkbox types */\n options?: Array<{\n value: string | number;\n label: string;\n disabled?: boolean;\n }>;\n /** Validation function */\n validator?: (value: any, formData: T) => string | null;\n /** Conditional function to show/hide field */\n conditional?: (formData: T) => boolean;\n /** Whether field can be empty */\n allowEmpty?: boolean;\n /** Remove field from form data when empty */\n removeIfEmpty?: boolean;\n /**\n * Uitleg onder het veld: waarom bestaat dit veld, of wat is de consequentie van de\n * keuze. Voor velden waar het label de vraag niet volledig kan stellen — een\n * groep-`description` is te grof zodra een groep meerdere velden heeft.\n */\n help?: string;\n /** Whether field is hidden */\n hidden?: boolean;\n /** Whether field is required */\n required?: boolean;\n /** Whether field is disabled */\n disabled?: boolean;\n /** Custom component renderer */\n customComponent?: (props: {\n value: any;\n onChange: (value: any) => void;\n error?: string;\n disabled?: boolean;\n }) => React.ReactNode;\n /** Additional props to pass to the field component */\n fieldProps?: Record<string, any>;\n\n /** For 'array' type, defines the fields for each item in the array */\n arrayFields?: FormGroupItem<any>[];\n\n /** For 'select' type, whether the select should be searchable */\n searchable?: boolean;\n\n /** For 'select' type, whether the select should be multiple */\n multiple?: boolean;\n\n allowCreate?: boolean;\n\n // todo: add support for array of objects\n}\n\nexport interface FormGroup<T = any> {\n /** Group identifier */\n id: string;\n /**\n * Group title. Optional: a form that is one unbroken block of fields has no\n * heading to give, and the label column already renders empty when it is\n * absent — the type was simply stricter than the component.\n */\n title?: string;\n /** Group description */\n description?: string;\n /** Group items */\n items: FormGroupItem<T>[];\n /** Conditional function to show/hide group */\n conditional?: (formData: T) => boolean;\n /** Group layout */\n layout?: \"grid\" | \"flex\";\n /** Number of columns for grid layout */\n columns?: number;\n /** Additional CSS classes */\n className?: string;\n}\n\nexport interface FormButtonProps {\n /** Button label */\n label: string;\n /** Button variant */\n variant?: \"primary\" | \"secondary\" | \"outline\" | \"ghost\" | \"destructive\";\n /** Button size */\n size?: \"sm\" | \"md\" | \"lg\";\n /** Whether button is disabled */\n disabled?: boolean;\n /** Additional CSS classes */\n className?: string;\n}\n\nexport interface FormProps<T = Record<string, any>> {\n /** Form groups */\n groups: FormGroup<T>[];\n /** Initial form data */\n data?: Partial<T>;\n /** Form submit handler */\n onSubmit?: (data: T, transformedData?: any) => void | Promise<void>;\n /** Form cancel handler */\n onCancel?: () => void;\n /** Form change handler */\n onChange?: (data: Partial<T>, changedField?: keyof T) => void;\n /** Data transformation function (called before submit) */\n transform?: (data: T) => any;\n /** Form validation function */\n validate?: (data: T) => Record<keyof T, string> | null;\n /** Submit button props */\n submitButton?: FormButtonProps;\n /** Cancel button props */\n cancelButton?: FormButtonProps;\n /** Whether to show buttons */\n showButtons?: boolean;\n /** Form layout */\n layout?: \"vertical\" | \"horizontal\";\n /** Form size */\n size?: \"sm\" | \"md\" | \"lg\" | \"full\";\n /** Whether form is loading */\n loading?: boolean;\n /** Additional CSS classes */\n className?: string;\n /**\n * Form ref. Includes `| null` because that is what React 19's\n * `useRef<HTMLFormElement>(null)` produces; without it every caller has to\n * cast at the call site.\n */\n ref?: React.RefObject<HTMLFormElement | null>;\n /** SDK instance */\n sdk?: InternalSDK<any>;\n}\n\n/**\n * Generic Form component with groups, validation, and conditional rendering\n */\nexport const Form = <T extends Record<string, any>>({\n groups,\n data: externalData,\n onSubmit,\n onCancel,\n onChange,\n transform,\n validate,\n submitButton = { label: \"Submit\", variant: \"primary\" },\n cancelButton = { label: \"Cancel\", variant: \"outline\" },\n showButtons = true,\n layout = \"vertical\",\n size = \"md\",\n loading = false,\n className,\n ref,\n sdk,\n}: FormProps<T>) => {\n const [formData, setFormData] = useState<Partial<T>>(externalData || {});\n const [errors, setErrors] = useState<Record<string, string>>({});\n const [touched, setTouched] = useState<Record<string, boolean>>({});\n\n // Update internal data when external data changes\n useEffect(() => {\n if (externalData) {\n setFormData({ ...externalData });\n }\n }, [externalData]);\n\n // Validate a single field\n const validateField = useCallback(\n (name: keyof T, value: any, currentData: Partial<T>) => {\n const field = groups\n .flatMap((group) => group.items)\n .find((item) => item.name === name);\n\n if (!field) return null;\n\n // Required validation\n if (\n field.required &&\n (value === undefined || value === null || value === \"\")\n ) {\n return `${field.label} is required`;\n }\n\n if (field.type === \"array\") {\n if (field.required && (!value || value.length === 0)) {\n return `${field.label} cannot be empty.`;\n }\n if (value && !Array.isArray(value)) {\n return `${field.label} must be an array.`;\n }\n\n if (Array.isArray(value) && field.arrayFields) {\n const arrayErrors: Record<string, any>[] = [];\n let hasErrors = false;\n value.forEach((row, index) => {\n const rowErrors: Record<string, string> = {};\n for (const subField of field.arrayFields!) {\n const subFieldValue = row?.[subField.name];\n if (\n subField.required &&\n (subFieldValue === undefined ||\n subFieldValue === null ||\n subFieldValue === \"\")\n ) {\n rowErrors[\n subField.name as string\n ] = `${subField.label} is required`;\n hasErrors = true;\n } else if (subField.validator) {\n const error = subField.validator(subFieldValue, row);\n if (error) {\n rowErrors[subField.name as string] = error;\n hasErrors = true;\n }\n }\n }\n arrayErrors[index] = rowErrors;\n });\n\n if (hasErrors) {\n return JSON.stringify(arrayErrors);\n }\n }\n }\n\n // Custom validation\n if (field.validator) {\n return field.validator(value, currentData as T);\n }\n\n return null;\n },\n [groups]\n );\n\n // Handle field change\n const handleFieldChange = useCallback(\n (name: keyof T, value: any) => {\n let newData = setValueByPath(\n formData as object,\n name as string,\n value\n ) as Partial<T>;\n\n // Handle removeIfEmpty\n const field = groups.flatMap((g) => g.items).find((i) => i.name === name);\n if (\n field?.removeIfEmpty &&\n (value === undefined || value === null || value === \"\")\n ) {\n newData = unsetByPath(newData as object, name as string) as Partial<T>;\n }\n\n setFormData(newData);\n setTouched((prev) => ({ ...prev, [name]: true }));\n\n // Validate field\n const error = validateField(name, value, newData);\n setErrors((prev) => ({\n ...prev,\n [name]: error || \"\",\n }));\n\n // Call onChange callback\n onChange?.(newData, name);\n },\n [formData, groups, validateField, onChange]\n );\n\n // Handle form submission\n const handleSubmit = useCallback(\n async (e: React.FormEvent) => {\n e.preventDefault();\n\n if (loading) return;\n\n // Validate all fields\n const newErrors: Record<string, string> = {};\n const allFields = groups.flatMap((group) => group.items);\n\n for (const field of allFields) {\n // Skip hidden or conditional fields\n if (\n field.hidden ||\n (field.conditional && !field.conditional(formData as T))\n ) {\n continue;\n }\n\n const error = validateField(\n field.name,\n getValueByPath<Partial<T>>(formData, field.name),\n formData\n );\n if (error) {\n newErrors[field.name as string] = error;\n }\n }\n\n // Run form-level validation\n if (validate) {\n const formErrors = validate(formData as T);\n if (formErrors) {\n Object.assign(newErrors, formErrors);\n }\n }\n\n setErrors(newErrors);\n\n // If there are errors, don't submit\n if (Object.keys(newErrors).some((key) => newErrors[key])) {\n return;\n }\n\n // Transform data if needed\n const finalData = transform ? transform(formData as T) : formData;\n\n // Submit form\n await onSubmit?.(formData as T, finalData);\n },\n [formData, groups, validateField, validate, transform, onSubmit, loading]\n );\n\n // Render field based on type\n const renderField = useCallback(\n (item: FormGroupItem<T>) => {\n const value = getValueByPath<Partial<T>>(formData, item.name) as\n | string\n | undefined;\n const error = touched[item.name as string]\n ? errors[item.name as string]\n : undefined;\n const isDisabled = item.disabled || loading;\n\n const commonProps = {\n value: value || \"\",\n disabled: isDisabled,\n required: item.required,\n placeholder: item.placeholder,\n ...item.fieldProps,\n };\n\n switch (item.type) {\n case \"text\":\n case \"email\":\n case \"password\":\n case \"number\":\n case \"tel\":\n case \"url\":\n case \"color\":\n return (\n <TextField\n {...commonProps}\n onChange={(e) => handleFieldChange(item.name, e.target.value)}\n type={item.textType || item.type}\n {...autofillProps(item.autocomplete)}\n error={error}\n size={size}\n />\n );\n\n case \"textarea\":\n return (\n <TextArea\n {...commonProps}\n onChange={(e) => handleFieldChange(item.name, e.target.value)}\n rows={item.rows ?? 4}\n error={error}\n size={size}\n />\n );\n\n case \"select\":\n return (\n <Select\n {...commonProps}\n onChange={(e) => handleFieldChange(item.name, e)}\n options={(item.options || []).map((option) => ({\n ...option,\n value: String(option.value),\n }))}\n searchable={item.searchable}\n multiple={item.multiple}\n allowCreate={item.allowCreate}\n error={error}\n size={size}\n />\n );\n\n // A short, fixed set of mutually exclusive values — priority, a scope,\n // a status. All options visible at once beats a dropdown you have to\n // open to learn what the choices even are.\n case \"segmented\":\n return (\n <SegmentedToggle\n aria-label={item.label}\n value={value == null ? \"\" : String(value)}\n onChange={(next) => handleFieldChange(item.name, next)}\n options={(item.options || []).map((option) => ({\n value: String(option.value),\n label: option.label,\n }))}\n size={size === \"sm\" ? \"sm\" : \"md\"}\n className={item.disabled ? \"pointer-events-none opacity-50\" : undefined}\n />\n );\n\n case \"checkbox\":\n return (\n <Checkbox\n {...commonProps}\n label={item.label}\n checked={Boolean(value)}\n onChange={(e) => handleFieldChange(item.name, e.target.checked)}\n size={size}\n />\n );\n\n case \"radio\":\n return (\n <div className=\"flex flex-col gap-2\">\n {item.options?.map((option) => (\n <label\n key={option.value}\n // gap-3 like Checkbox: a radio row and a checkbox row in the\n // same form must sit the same distance from their label.\n className=\"flex cursor-pointer items-center gap-3 text-base text-text\"\n >\n <input\n type=\"radio\"\n name={item.name as string}\n value={option.value}\n checked={value === option.value}\n onChange={() => handleFieldChange(item.name, option.value)}\n disabled={isDisabled || option.disabled}\n className=\"size-checkbox shrink-0 rounded-xs border border-border-strong bg-surface-input accent-accent focus-visible:outline-none focus-visible:focus-ring\"\n />\n {option.label}\n </label>\n ))}\n </div>\n );\n\n case \"date\":\n return (\n <DatePicker\n {...commonProps}\n value={value ? new Date(value) : null}\n onChange={(date) => handleFieldChange(item.name, date)}\n size={size}\n />\n );\n\n case \"file\":\n return (\n <StorageInput\n {...commonProps}\n value={value}\n onChange={(pointer) => handleFieldChange(item.name, pointer)}\n error={error}\n onListFiles={(filters) => sdk?.http.invoke<{ data: FilePointer[] }>({\n method: \"POST\",\n action: \"storage.file.list\",\n body: filters,\n })}\n onListMounts={() => sdk?.http.invoke<{ data: VirtualMount[] }>({\n method: \"GET\",\n action: \"storage.mount\",\n })}\n onUploadFile={(payload) => sdk?.http.invoke<{ data: FilePointer }>({\n method: \"POST\",\n action: \"storage.file.upload\",\n body: payload,\n })}\n onDownloadFile={(fileId) => sdk?.http.invoke<Uint8Array>({\n method: \"GET\",\n action: `storage.file.${fileId}.download`,\n })}\n onRegisterFile={(payload) => sdk?.http.invoke<{ data: FilePointer }>({\n method: \"POST\",\n action: \"storage.file.folder\",\n body: payload,\n })}\n />\n );\n\n case \"folder\":\n return (\n <FolderSelect\n value={(value as unknown as FolderDestination) || {}}\n onChange={(v) => handleFieldChange(item.name, v)}\n onListFolders={() => sdk?.http.invoke<{ data: VirtualMount[] }>({\n method: \"GET\",\n action: \"storage.mount\",\n })}\n disabled={isDisabled}\n size={size}\n placeholder={item.placeholder}\n />\n );\n\n case \"custom\":\n return item.customComponent?.({\n value,\n onChange: (newValue) => handleFieldChange(item.name, newValue),\n error,\n disabled: isDisabled,\n });\n\n case \"array\": {\n const arrayValue = (value || []) as any[];\n let arrayErrors: Record<string, string>[] = [];\n if (typeof error === \"string\" && error.startsWith(\"[\")) {\n try {\n arrayErrors = JSON.parse(error);\n } catch (e) {\n // ignore parse error\n }\n }\n\n const handleAddItem = () => {\n handleFieldChange(item.name, [...arrayValue, {}]);\n };\n\n const handleRemoveItem = (index: number) => {\n handleFieldChange(\n item.name,\n arrayValue.filter((_, i) => i !== index)\n );\n };\n\n const handleSubFieldChange = (\n index: number,\n fieldName: string,\n fieldValue: any\n ) => {\n const newArray = [...arrayValue];\n newArray[index] = {\n ...newArray[index],\n [fieldName]: fieldValue,\n };\n handleFieldChange(item.name, newArray);\n };\n\n return (\n <div className=\"flex flex-col gap-2\">\n {arrayValue.map((row, index) => (\n <div key={index} className=\"flex items-start gap-2\">\n <div className=\"grid flex-1 gap-2 sm:grid-cols-2\">\n {item.arrayFields?.map((subField) => {\n const subFieldError =\n arrayErrors?.[index]?.[subField.name as string];\n return (\n <div\n key={subField.name as string}\n className=\"flex flex-col gap-1\"\n >\n {index === 0 && (\n <label className=\"block text-xs font-semibold uppercase tracking-label text-text-subtle\">\n {subField.label}\n {subField.required && (\n <span className=\"ml-1 text-danger-fg\">*</span>\n )}\n </label>\n )}\n {/* Note: Duplicating field rendering logic here. Could be refactored. */}\n {(() => {\n const commonSubFieldProps = {\n value: row?.[subField.name] || \"\",\n disabled: isDisabled,\n required: subField.required,\n placeholder: subField.placeholder,\n ...subField.fieldProps,\n };\n switch (subField.type) {\n case \"text\":\n case \"email\":\n case \"password\":\n case \"number\":\n case \"tel\":\n case \"url\":\n return (\n <TextField\n {...commonSubFieldProps}\n onChange={(e) =>\n handleSubFieldChange(\n index,\n subField.name as string,\n e.target.value\n )\n }\n type={subField.textType || subField.type}\n {...autofillProps(subField.autocomplete)}\n error={subFieldError}\n size={size}\n />\n );\n case \"textarea\":\n return (\n <TextArea\n {...commonSubFieldProps}\n onChange={(e) =>\n handleSubFieldChange(\n index,\n subField.name as string,\n e.target.value\n )\n }\n rows={subField.rows ?? 4}\n error={subFieldError}\n size={size}\n />\n );\n case \"select\":\n return (\n <Select\n {...commonSubFieldProps}\n onChange={(e) =>\n handleSubFieldChange(\n index,\n subField.name as string,\n e\n )\n }\n options={(subField.options || []).map(\n (option) => ({\n ...option,\n value: String(option.value),\n })\n )}\n searchable={subField.searchable}\n multiple={subField.multiple}\n allowCreate={subField.allowCreate}\n error={subFieldError}\n size={size}\n />\n );\n case \"checkbox\":\n return (\n <Checkbox\n {...commonSubFieldProps}\n checked={Boolean(row?.[subField.name])}\n onChange={(e) =>\n handleSubFieldChange(\n index,\n subField.name as string,\n e.target.checked\n )\n }\n size={size}\n />\n );\n case \"radio\":\n return (\n <div className=\"flex flex-col gap-2\">\n {subField.options?.map((option) => (\n <label\n key={option.value}\n className=\"flex cursor-pointer items-center gap-2 text-base text-text\"\n >\n <input\n type=\"radio\"\n name={`${item.name as string\n }.${index}.${subField.name as string\n }`}\n value={option.value}\n checked={\n row?.[subField.name] ===\n option.value\n }\n onChange={() =>\n handleSubFieldChange(\n index,\n subField.name as string,\n option.value\n )\n }\n disabled={\n isDisabled || option.disabled\n }\n className=\"size-checkbox shrink-0 rounded-xs border border-border-strong bg-surface-input accent-accent focus-visible:outline-none focus-visible:focus-ring\"\n />\n {option.label}\n </label>\n ))}\n </div>\n );\n case \"date\": {\n const dateValue = row?.[subField.name];\n return (\n <DatePicker\n {...commonSubFieldProps}\n value={\n dateValue ? new Date(dateValue) : null\n }\n onChange={(date) =>\n handleSubFieldChange(\n index,\n subField.name as string,\n date\n )\n }\n size={size}\n />\n );\n }\n case \"custom\":\n return subField.customComponent?.({\n value: row?.[subField.name],\n onChange: (newValue) =>\n handleSubFieldChange(\n index,\n subField.name as string,\n newValue\n ),\n error: subFieldError,\n disabled: isDisabled,\n });\n // Add other field types here as needed\n default:\n return (\n <p>\n Unsupported field type in array:{\" \"}\n {subField.type}\n </p>\n );\n }\n })()}\n {subFieldError && (\n <p className=\"text-xs text-danger-fg\">{subFieldError}</p>\n )}\n </div>\n );\n })}\n </div>\n <Button\n type=\"button\"\n iconOnly\n variant=\"ghost\"\n size=\"md\"\n aria-label={`${item.label} verwijderen`}\n onClick={() => handleRemoveItem(index)}\n disabled={isDisabled}\n className={cn(\"shrink-0\", index === 0 && \"mt-5\")}\n >\n <Trash2 className=\"size-icon-md\" />\n </Button>\n </div>\n ))}\n <Button\n type=\"button\"\n variant=\"secondary\"\n leftIcon={<Plus className=\"size-icon-sm\" />}\n onClick={handleAddItem}\n disabled={isDisabled}\n >\n {item.label} toevoegen\n </Button>\n </div>\n );\n }\n\n default:\n return null;\n }\n },\n [formData, touched, errors, loading, size, handleFieldChange]\n );\n\n // Render form group\n const renderGroup = useCallback(\n (group: FormGroup<T>) => {\n // Check group conditional\n if (group.conditional && !group.conditional(formData as T)) {\n return null;\n }\n\n const visibleItems = group.items.filter((item) => {\n if (item.hidden) return false;\n if (item.conditional && !item.conditional(formData as T)) return false;\n return true;\n });\n\n if (visibleItems.length === 0) return null;\n\n const groupClasses = cn(\n group.layout === \"flex\" ? \"flex flex-wrap gap-3.5\" : \"grid gap-3.5\",\n group.layout !== \"flex\" && {\n \"grid-cols-1\": !group.columns || group.columns === 1,\n \"grid-cols-2\": group.columns === 2,\n \"grid-cols-3\": group.columns === 3,\n \"grid-cols-4\": group.columns === 4,\n },\n group.className\n );\n\n return (\n // A band across the page, closed off with a hairline — no card. The\n // form *is* the page now, so a panel around each section would be a\n // second surface on top of the one it already sits on.\n <FormSection\n key={group.id}\n title={group.title}\n description={group.description}\n className=\"not-last:border-b not-last:border-border-subtle\"\n >\n {/* Group Items */}\n <div>\n <div className={groupClasses}>\n {visibleItems.map((item) => {\n const fieldError = touched[item.name as string]\n ? errors[item.name as string]\n : undefined;\n\n return (\n <div\n key={item.name as string}\n className={cn(\n \"flex min-w-0 flex-col gap-1.5\",\n item.type === \"checkbox\" && \"justify-center\"\n )}\n style={{\n width: typeof item.width === \"string\" ? item.width : undefined,\n gridColumn:\n typeof item.width === \"number\"\n ? `span ${item.width} / span ${item.width}`\n : undefined,\n }}\n >\n {/* Field Label — checkbox carries its own label on the right */}\n {item.type !== \"custom\" && item.type !== \"checkbox\" && (\n <label className=\"block text-sm font-medium text-text-muted\">\n {item.label}\n {item.required && (\n <span className=\"ml-1 text-danger-fg\">*</span>\n )}\n </label>\n )}\n\n {/* Field Input */}\n {renderField(item)}\n\n {/* Uitleg onder het veld (los van een validatiefout). */}\n {item.help && !fieldError && (\n <p className=\"text-xs leading-4 text-text-subtle\">{item.help}</p>\n )}\n </div>\n );\n })}\n </div>\n </div>\n </FormSection>\n );\n },\n [formData, touched, errors, renderField]\n );\n\n // No panel chrome: the page (or the card the page sits in) is the surface.\n // `size` is a reading width, nothing more — `md` is the standard form column.\n const formClasses = cn(\n {\n \"max-w-settings\": size === \"sm\",\n \"max-w-form\": size === \"md\",\n \"max-w-6xl\": size === \"lg\",\n \"max-w-full\": size === \"full\",\n },\n className\n );\n\n const buttonSize = size === \"full\" ? \"md\" : size;\n\n return (\n <form ref={ref} onSubmit={handleSubmit} className={formClasses}>\n {/* Implicit submission. A form with several fields and no submit button\n inside it ignores Enter entirely — which is what happens whenever the\n save button lives in a page header (showButtons={false}). This hidden\n button is the form's default button, so Enter in a text field submits\n the way it does everywhere else. */}\n {!showButtons && <button type=\"submit\" className=\"hidden\" tabIndex={-1} aria-hidden />}\n\n {/* Form Groups — bands down the page, separated by a hairline */}\n <div className=\"flex flex-col\">{groups.map(renderGroup)}</div>\n\n {/* Footer. Only when it has something in it: without the panel around the\n form, an empty footer is a rule hanging under the last section. */}\n {showButtons && (\n <div className=\"flex items-center gap-2 border-t border-border-subtle py-4\">\n <>\n <div className=\"ml-auto\" />\n {onCancel && (\n <Button\n type=\"button\"\n variant={cancelButton.variant ?? \"ghost\"}\n size={cancelButton.size || buttonSize}\n disabled={cancelButton.disabled || loading}\n onClick={onCancel}\n className={cancelButton.className}\n >\n {cancelButton.label}\n </Button>\n )}\n\n <Button\n type=\"submit\"\n variant={submitButton.variant}\n size={submitButton.size || buttonSize}\n disabled={submitButton.disabled || loading}\n loading={loading}\n className={submitButton.className}\n >\n {submitButton.label}\n </Button>\n </>\n </div>\n )}\n </form>\n );\n};\n","import React from \"react\";\nimport { Button } from \"../action/Button\";\nimport { Text } from \"../typography/Text\";\nimport { Modal } from \"./Modal\";\n\nexport interface ConfirmDialogProps {\n open: boolean;\n title: string;\n /** What is about to happen, and what it costs if it is wrong. */\n description?: React.ReactNode;\n confirmLabel?: string;\n cancelLabel?: string;\n /** `danger` for anything that destroys or detaches something. */\n tone?: \"default\" | \"danger\";\n /** Disables both buttons and puts the confirm button in its loading state. */\n loading?: boolean;\n onConfirm: () => void;\n onCancel: () => void;\n}\n\n/**\n * Confirmation before a destructive or irreversible action.\n *\n * Replaces `window.confirm`, which blocks the main thread, cannot be styled,\n * cannot be translated, and is suppressed outright in some embedded contexts.\n * Note the shape difference: `confirm()` returns a boolean inline, so callers\n * written as `if (!confirm(...)) return;` have to split into a request step\n * and a confirm step.\n *\n * @example\n * ```tsx\n * <ConfirmDialog\n * open={pendingDelete !== null}\n * tone=\"danger\"\n * title={t(\"channel_delete_title\")}\n * description={t(\"channel_delete_description\")}\n * confirmLabel={t(\"delete\")}\n * onConfirm={() => remove(pendingDelete!)}\n * onCancel={() => setPendingDelete(null)}\n * />\n * ```\n */\nexport function ConfirmDialog({\n open,\n title,\n description,\n confirmLabel = \"Bevestigen\",\n cancelLabel = \"Annuleren\",\n tone = \"default\",\n loading = false,\n onConfirm,\n onCancel,\n}: ConfirmDialogProps) {\n return (\n <Modal\n open={open}\n onClose={onCancel}\n title={title}\n size=\"sm\"\n footer={\n <div className=\"flex w-full items-center justify-end gap-2\">\n <Button variant=\"ghost\" onClick={onCancel} disabled={loading}>\n {cancelLabel}\n </Button>\n <Button\n variant={tone === \"danger\" ? \"destructive\" : \"primary\"}\n onClick={onConfirm}\n loading={loading}\n >\n {confirmLabel}\n </Button>\n </div>\n }\n >\n {description && <Text color=\"secondary\">{description}</Text>}\n </Modal>\n );\n}\n","import React from 'react';\nimport { X } from \"lucide-react\";\nimport { Icon } from \"../content/Icon\";\nimport { cn } from '../utils/cn';\n\n/**\n * `color` is deliberately omitted from the inherited HTML attributes. It is a\n * legacy HTML attribute, so `<Badge color=\"success\">` used to type-check while\n * doing nothing at all — the badge silently rendered as `default`. Omitting it\n * turns that mistake into a compile error pointing at `variant`.\n */\nexport interface BadgeProps extends Omit<React.HTMLAttributes<HTMLSpanElement>, 'color'> {\n /**\n * The visual variant of the badge\n */\n variant?: 'default' | 'primary' | 'secondary' | 'success' | 'warning' | 'error' | 'info' | 'note';\n \n /**\n * The size of the badge\n */\n size?: 'sm' | 'md' | 'lg';\n \n /**\n * Whether the badge should have a dot indicator\n */\n dot?: boolean;\n \n /**\n * Icon to display in the badge\n */\n icon?: React.ReactNode;\n \n /**\n * Whether the badge can be dismissed\n */\n dismissible?: boolean;\n \n /**\n * Callback fired when the badge is dismissed\n */\n onDismiss?: () => void;\n}\n\n// Semantic, token-driven (mode-aware via CSS custom properties — no dark: overrides needed)\nconst badgeVariants = {\n default: 'bg-surface-hover text-text',\n primary: 'bg-accent-soft text-accent',\n secondary: 'bg-surface-hover text-text-muted',\n success: 'bg-success-soft text-success-fg',\n warning: 'bg-warning-soft text-warning-fg',\n error: 'bg-danger-soft text-danger-fg',\n info: 'bg-info-soft text-info-fg',\n // Internal-note amber. Never for customer-visible content.\n note: 'bg-note-soft text-note',\n};\n\nconst badgeSizes = {\n sm: 'px-2 py-0.5 text-xs',\n md: 'px-2.5 py-1 text-sm',\n lg: 'px-3 py-1.5 text-base',\n};\n\nconst dotColors = {\n default: 'bg-surface-hover',\n primary: 'bg-accent',\n secondary: 'bg-surface-hover',\n success: 'bg-success',\n warning: 'bg-warning',\n error: 'bg-danger',\n info: 'bg-info',\n note: 'bg-note',\n};\n\n/**\n * Badge component for displaying status indicators and labels\n * \n * @example\n * ```tsx\n * <Badge variant=\"success\">Active</Badge>\n * \n * <Badge variant=\"warning\" dot>\n * Pending\n * </Badge>\n * \n * <Badge variant=\"error\" dismissible onDismiss={() => console.log('dismissed')}>\n * Error\n * </Badge>\n * \n * <Badge variant=\"primary\" icon={<StarIcon />}>\n * Featured\n * </Badge>\n * ```\n */\nexport function Badge({\n variant = 'default',\n size = 'md',\n dot = false,\n icon,\n dismissible = false,\n onDismiss,\n className,\n children,\n ...props\n}: BadgeProps) {\n return (\n <span\n className={cn(\n // Base styles\n 'inline-flex items-center font-medium rounded-full',\n \n // Variant styles\n badgeVariants[variant],\n \n // Size styles\n badgeSizes[size],\n \n className\n )}\n {...props}\n >\n {dot && (\n <span\n className={cn(\n 'w-2 h-2 rounded-full mr-1.5',\n dotColors[variant]\n )}\n />\n )}\n \n {icon && (\n <span className={cn('flex-shrink-0', children && 'mr-1')}>\n {icon}\n </span>\n )}\n \n {children}\n \n {dismissible && onDismiss && (\n <button\n onClick={onDismiss}\n className=\"ml-1.5 flex-shrink-0 hover:opacity-70 transition-opacity\"\n aria-label=\"Remove badge\"\n >\n <Icon icon={X} size=\"xs\" color=\"current\" />\n </button>\n )}\n </span>\n );\n} ","import { ReactNode } from 'react';\nimport { cn } from '../utils/cn';\n\n/**\n * What is about to appear here. A placeholder only does its job if it has the\n * geometry of the thing it stands in for: the default `text` shape under a form\n * or a list announces a heading and two paragraphs, and the real content then\n * shoves everything sideways when it lands.\n */\nexport type ContentLoadingShape =\n | \"text\"\n | \"table\"\n | \"list\"\n | \"form\"\n | \"menu\"\n | \"cards\";\n\nexport interface ContentLoadingProps {\n /**\n * `page` (default) fills the route with its own `<main>` shell and padding.\n * `inline` drops both, so the skeleton can sit inside an existing panel,\n * card or scroll container without nesting a second `<main>` landmark.\n */\n variant?: \"page\" | \"inline\";\n\n /** The shape of what is coming. Defaults to `text`. */\n shape?: ContentLoadingShape;\n\n /** Rows/items/fields/cards to draw, depending on `shape`. */\n rows?: number;\n\n /** Columns, for `table` and `cards`. */\n columns?: number;\n\n /**\n * Optional custom skeleton content (overrides default)\n */\n children?: ReactNode;\n\n className?: string;\n\n /** @deprecated Pass `shape=\"table\"`. */\n showTableSkeleton?: boolean;\n /** @deprecated Pass `columns`. */\n tableColumns?: number;\n /** @deprecated Pass `rows`. */\n tableRows?: number;\n}\n\n/** One placeholder bar. Uneven widths read as text rather than as a progress bar. */\nconst Bar = ({ className }: { className?: string }) => (\n <span className={cn(\"block rounded-xs bg-surface-hover\", className)} />\n);\n\nconst WIDTHS = [\"62%\", \"44%\", \"74%\", \"52%\", \"68%\", \"48%\", \"80%\", \"56%\"];\n\nfunction Shape({ shape, rows, columns }: { shape: ContentLoadingShape; rows: number; columns: number }) {\n switch (shape) {\n case \"table\":\n return (\n <div className=\"overflow-hidden rounded-lg ring-1 ring-border\">\n <div\n className=\"grid gap-2 bg-surface-hover p-3\"\n style={{ gridTemplateColumns: `repeat(${columns}, minmax(0, 1fr))` }}\n >\n {Array.from({ length: columns }).map((_, i) => (\n <Bar key={`h-${i}`} className=\"h-4 w-2/3 bg-border-strong\" />\n ))}\n </div>\n {Array.from({ length: rows }).map((_, r) => (\n <div\n key={`r-${r}`}\n className=\"grid gap-2 border-t border-border-subtle p-3\"\n style={{ gridTemplateColumns: `repeat(${columns}, minmax(0, 1fr))` }}\n >\n {Array.from({ length: columns }).map((_, c) => (\n <Bar key={`c-${r}-${c}`} className=\"h-4 w-full\" />\n ))}\n </div>\n ))}\n </div>\n );\n\n case \"list\":\n return (\n <div className=\"flex flex-col divide-y divide-border-subtle rounded-lg ring-1 ring-border\">\n {Array.from({ length: rows }).map((_, i) => (\n <div key={i} className=\"flex items-center gap-3 p-3\">\n <Bar className=\"size-avatar-sm shrink-0 rounded-full\" />\n <div className=\"flex min-w-0 flex-1 flex-col gap-1.5\">\n <Bar className=\"h-3\" />\n <Bar className=\"h-2.5 opacity-70\" />\n </div>\n </div>\n ))}\n </div>\n );\n\n case \"form\":\n // Label above, field below — the pair a form actually renders, so the\n // fields do not jump when they replace this.\n return (\n <div className=\"flex flex-col gap-5\">\n {Array.from({ length: rows }).map((_, i) => (\n <div key={i} className=\"flex flex-col gap-2\">\n <Bar className=\"h-2.5 w-28\" />\n <Bar className=\"h-control-md w-full rounded-md\" />\n </div>\n ))}\n </div>\n );\n\n case \"menu\":\n // The same geometry the sidebar menu draws: a caption, then rows at item\n // height with room for the icon.\n return (\n <div className=\"flex flex-col gap-px\">\n <div className=\"px-2.5 pb-2 pt-5\">\n <Bar className=\"h-2 w-16\" />\n </div>\n {Array.from({ length: rows }).map((_, i) => (\n <div key={i} className=\"flex h-row-md items-center gap-2.5 px-2.5\">\n <Bar className=\"size-4 shrink-0\" />\n <Bar className=\"h-2\" />\n </div>\n ))}\n </div>\n );\n\n case \"cards\":\n return (\n <div\n className=\"grid gap-4\"\n style={{ gridTemplateColumns: `repeat(${columns}, minmax(0, 1fr))` }}\n >\n {Array.from({ length: rows * columns }).map((_, i) => (\n <div key={i} className=\"flex flex-col gap-2 rounded-lg p-4 ring-1 ring-border\">\n <Bar className=\"h-3 w-1/2\" />\n <Bar className=\"h-2.5\" />\n <Bar className=\"h-2.5 w-3/4 opacity-70\" />\n </div>\n ))}\n </div>\n );\n\n case \"text\":\n default:\n return (\n <div className=\"flex flex-col gap-6\">\n <Bar className=\"h-6 w-1/4\" />\n <div className=\"flex flex-col gap-2\">\n {Array.from({ length: rows }).map((_, i) => (\n <Bar key={i} className=\"h-4\" />\n ))}\n </div>\n </div>\n );\n }\n}\n\n/** Sensible counts per shape, so a call site only names the shape. */\nconst DEFAULT_ROWS: Record<ContentLoadingShape, number> = {\n text: 2,\n table: 8,\n list: 6,\n form: 5,\n menu: 4,\n cards: 2,\n};\n\nexport function ContentLoading({\n variant = \"page\",\n shape,\n rows,\n columns,\n children,\n className,\n showTableSkeleton = false,\n tableColumns,\n tableRows,\n}: ContentLoadingProps) {\n // The deprecated table props still decide the shape when no `shape` is given,\n // so existing call sites keep rendering what they always did.\n const resolvedShape: ContentLoadingShape = shape ?? (showTableSkeleton ? \"table\" : \"text\");\n const resolvedRows = rows ?? tableRows ?? DEFAULT_ROWS[resolvedShape];\n const resolvedColumns = columns ?? tableColumns ?? (resolvedShape === \"cards\" ? 3 : 6);\n\n // `inline` renders the skeleton bare; `page` wraps it in the route shell.\n const inner = (\n <div className={cn(\"w-full animate-pulse\", className)} aria-hidden>\n {children ?? (\n <Shape shape={resolvedShape} rows={resolvedRows} columns={resolvedColumns} />\n )}\n </div>\n );\n\n if (variant === \"inline\") return inner;\n\n return <main className=\"flex-1 bg-surface p-6\">{inner}</main>;\n}\n","import React from \"react\";\nimport { cn } from \"../utils/cn\";\n\nexport interface EmptyStateProps extends Omit<React.HTMLAttributes<HTMLDivElement>, \"title\"> {\n /** Leading glyph or icon (e.g. a check for the focus \"queue empty\" state). */\n icon?: React.ReactNode;\n /** Tint of the icon disc. */\n tone?: \"neutral\" | \"success\";\n /** Headline. */\n title: React.ReactNode;\n /** Supporting copy. */\n description?: React.ReactNode;\n /** Action buttons row. */\n actions?: React.ReactNode;\n /** Render inside a raised card (focus \"done\" state) vs. plain centered block. */\n card?: boolean;\n}\n\nconst toneDisc: Record<NonNullable<EmptyStateProps[\"tone\"]>, string> = {\n neutral: \"bg-surface-hover text-text-muted\",\n success: \"bg-success-soft text-success-fg\",\n};\n\n/**\n * Centered empty / completion state (focus queue done, no-results lists).\n *\n * @example\n * ```tsx\n * <EmptyState card tone=\"success\" icon={<Icon icon={Check} size=\"lg\" />}\n * title=\"Wachtrij leeg — 7 afgehandeld\"\n * description=\"Nieuwe gesprekken verschijnen hier vanzelf.\"\n * actions={<Button>Terug naar Mijn dag</Button>} />\n * ```\n */\nexport function EmptyState({\n icon,\n tone = \"neutral\",\n title,\n description,\n actions,\n card = false,\n className,\n ...props\n}: EmptyStateProps) {\n return (\n <div\n className={cn(\n \"flex flex-col items-center gap-2.5 text-center\",\n card && \"rounded-lg border border-border bg-surface px-11 py-9 shadow-overlay\",\n className,\n )}\n {...props}\n >\n {icon != null && (\n <span className={cn(\"flex size-disc items-center justify-center rounded-full text-2xl\", toneDisc[tone])}>\n {icon}\n </span>\n )}\n <div className=\"text-lg font-semibold text-text\">{title}</div>\n {description && <div className=\"max-w-sm text-sm leading-relaxed text-text-muted\">{description}</div>}\n {actions && <div className=\"flex gap-2 pt-1.5\">{actions}</div>}\n </div>\n );\n}\n","import React from \"react\";\nimport { cn } from \"../utils/cn\";\n\nexport interface KbdProps extends React.HTMLAttributes<HTMLElement> {\n /** Key label, e.g. \"⌘K\", \"E\", \"↵\". */\n children: React.ReactNode;\n}\n\n/**\n * Keyboard-shortcut chip (the `⌘K` / `E` / `↵` hints in the redesign).\n *\n * @example\n * ```tsx\n * Zoeken <Kbd>⌘K</Kbd>\n * ```\n */\nexport function Kbd({ children, className, ...props }: KbdProps) {\n return (\n <kbd\n className={cn(\n \"inline-flex items-center rounded border border-border px-1.5 py-px text-xs font-medium leading-none text-text-muted\",\n className,\n )}\n {...props}\n >\n {children}\n </kbd>\n );\n}\n","import React from \"react\";\nimport { cn } from \"../utils/cn\";\n\nexport interface ProgressBarProps extends React.HTMLAttributes<HTMLDivElement> {\n /** Completion 0–100 (clamped). */\n value: number;\n /** Fill tone. */\n variant?: \"accent\" | \"success\";\n /** Track height. */\n size?: \"sm\" | \"md\";\n}\n\nconst trackSizes: Record<NonNullable<ProgressBarProps[\"size\"]>, string> = {\n sm: \"h-1\",\n md: \"h-1.5\",\n};\n\nconst fillVariants: Record<NonNullable<ProgressBarProps[\"variant\"]>, string> = {\n accent: \"bg-accent\",\n success: \"bg-success\",\n};\n\n/**\n * Slim determinate progress bar (focus queue progress, subtask completion).\n * Token-driven and mode-aware.\n *\n * @example\n * ```tsx\n * <ProgressBar value={40} />\n * <ProgressBar value={3 / 7 * 100} variant=\"success\" size=\"sm\" />\n * ```\n */\nexport function ProgressBar({ value, variant = \"accent\", size = \"md\", className, ...props }: ProgressBarProps) {\n const pct = Math.max(0, Math.min(100, value));\n return (\n <div\n role=\"progressbar\"\n aria-valuenow={Math.round(pct)}\n aria-valuemin={0}\n aria-valuemax={100}\n className={cn(\"w-full overflow-hidden rounded-full bg-surface-hover\", trackSizes[size], className)}\n {...props}\n >\n <div\n className={cn(\"h-full rounded-full transition-[width] duration-300 ease-out\", fillVariants[variant])}\n style={{ width: `${pct}%` }}\n />\n </div>\n );\n}\n","import React from 'react';\nimport { cn } from '../utils/cn';\n\nexport interface SpinnerProps extends React.HTMLAttributes<HTMLDivElement> {\n /**\n * The size of the spinner\n */\n size?: 'xs' | 'sm' | 'md' | 'lg' | 'xl';\n \n /**\n * The color variant of the spinner\n */\n variant?: 'primary' | 'secondary' | 'white' | 'current';\n \n /**\n * Optional label for accessibility\n */\n label?: string;\n \n /**\n * Whether to show the spinner with a label\n */\n showLabel?: boolean;\n}\n\nconst spinnerSizes = {\n xs: 'h-3 w-3',\n sm: 'h-4 w-4',\n md: 'h-6 w-6',\n lg: 'h-8 w-8',\n xl: 'h-12 w-12',\n};\n\nconst spinnerColors = {\n primary: 'text-accent',\n secondary: 'text-text-muted',\n white: 'text-white',\n current: 'text-current',\n};\n\nconst labelSizes = {\n xs: 'text-xs',\n sm: 'text-sm',\n md: 'text-sm',\n lg: 'text-base',\n xl: 'text-lg',\n};\n\n/**\n * Spinner component for loading states\n * \n * @example\n * ```tsx\n * <Spinner size=\"md\" variant=\"primary\" />\n * \n * <Spinner size=\"lg\" variant=\"primary\" showLabel label=\"Loading...\" />\n * \n * <Spinner size=\"sm\" variant=\"white\" />\n * ```\n */\nexport function Spinner({\n size = 'md',\n variant = 'primary',\n label = 'Loading...',\n showLabel = false,\n className,\n ...props\n}: SpinnerProps) {\n return (\n <div\n className={cn(\n 'inline-flex items-center',\n showLabel ? 'flex-col space-y-2' : '',\n className\n )}\n {...props}\n >\n <svg\n className={cn(\n 'animate-spin',\n spinnerSizes[size],\n spinnerColors[variant]\n )}\n fill=\"none\"\n viewBox=\"0 0 24 24\"\n aria-hidden={!showLabel}\n role={showLabel ? 'status' : undefined}\n >\n <circle\n className=\"opacity-25\"\n cx=\"12\"\n cy=\"12\"\n r=\"10\"\n stroke=\"currentColor\"\n strokeWidth=\"4\"\n />\n <path\n className=\"opacity-75\"\n fill=\"currentColor\"\n d=\"M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z\"\n />\n </svg>\n \n {showLabel && (\n <span\n className={cn(\n 'text-text-muted',\n labelSizes[size]\n )}\n >\n {label}\n </span>\n )}\n \n {/* Screen reader only text when label is not shown */}\n {!showLabel && (\n <span className=\"sr-only\">{label}</span>\n )}\n </div>\n );\n} ","import React from \"react\";\nimport { cn } from \"../utils/cn\";\n\nexport interface StatusDotProps {\n /**\n * Meaning, not colour. `neutral` is the off/idle state; `accent` marks\n * unread; the rest follow the status tokens.\n */\n tone?:\n | \"neutral\" | \"accent\" | \"success\" | \"warning\" | \"danger\" | \"info\" | \"note\"\n /** Identity without status — an inbox, a speaker. See --color-cat-*. */\n | \"cat-1\" | \"cat-2\" | \"cat-3\" | \"cat-4\" | \"cat-5\";\n /** Square instead of round — the marker style used for inbox identity. */\n shape?: \"round\" | \"square\";\n /** Slow pulse for something live: an active call, a running recording. */\n pulse?: boolean;\n /**\n * Accessible name. Without one the dot is decorative and hidden from\n * assistive tech, which is right when adjacent text already says the state.\n */\n label?: string;\n className?: string;\n}\n\nconst tones: Record<NonNullable<StatusDotProps[\"tone\"]>, string> = {\n neutral: \"bg-text-disabled\",\n accent: \"bg-accent\",\n success: \"bg-success\",\n warning: \"bg-warning\",\n danger: \"bg-danger\",\n info: \"bg-info\",\n note: \"bg-note\",\n \"cat-1\": \"bg-cat-1\",\n \"cat-2\": \"bg-cat-2\",\n \"cat-3\": \"bg-cat-3\",\n \"cat-4\": \"bg-cat-4\",\n \"cat-5\": \"bg-cat-5\",\n};\n\n/**\n * Small state marker: presence, session state, unread, live recording.\n *\n * Replaces a scatter of hand-rolled `h-2 w-2 rounded-full bg-green-500` spans\n * that used raw palette colours and disagreed on size (8px vs 10px).\n *\n * @example\n * ```tsx\n * <StatusDot tone=\"success\" label=\"Online\" />\n * <StatusDot tone=\"danger\" pulse label=\"Opname loopt\" />\n * ```\n */\nexport function StatusDot({\n tone = \"neutral\",\n shape = \"round\",\n pulse = false,\n label,\n className,\n}: StatusDotProps) {\n return (\n <span\n role={label ? \"img\" : undefined}\n aria-label={label}\n aria-hidden={label ? undefined : true}\n className={cn(\n \"inline-block size-dot shrink-0\",\n shape === \"round\" ? \"rounded-full\" : \"rounded-sm\",\n tones[tone],\n pulse && \"animate-pulse\",\n className\n )}\n />\n );\n}\n","import React from \"react\";\nimport { cn } from \"../utils/cn\";\n\nexport interface StepIndicatorProps {\n /** Step ids in order. Only the position matters; the ids identify `current`. */\n steps: string[];\n /** Id of the step being shown. Unknown ids render as \"not started\". */\n current: string;\n /**\n * `numbered` draws counted circles joined by a rule — use it when the user\n * needs to know how many steps are left. `dots` is the quieter bar, for a\n * flow whose heading already says where you are.\n */\n variant?: \"numbered\" | \"dots\";\n /**\n * Accessible name. Without one the indicator is treated as decorative, which\n * is right when a heading beside it already announces the current step.\n */\n label?: string;\n className?: string;\n}\n\n/**\n * Progress through a short, linear flow.\n *\n * @example\n * ```tsx\n * <StepIndicator steps={[\"provider\", \"channel\", \"owner\"]} current={step} />\n * <StepIndicator steps={[\"intent\", \"channel\", \"address\"]} current={step} variant=\"dots\" />\n * ```\n */\nexport function StepIndicator({\n steps,\n current,\n variant = \"numbered\",\n label,\n className,\n}: StepIndicatorProps) {\n const activeIndex = steps.indexOf(current);\n const shared = { role: label ? \"group\" : undefined, \"aria-label\": label, \"aria-hidden\": label ? undefined : true };\n\n if (variant === \"dots\") {\n return (\n <div {...shared} className={cn(\"flex items-center gap-1.5\", className)}>\n {steps.map((step, i) => (\n <span\n key={step}\n className={cn(\n \"h-step-bar rounded-full transition-all duration-fast ease-out\",\n i === activeIndex ? \"w-5 bg-accent\" : \"w-3.5\",\n i < activeIndex && \"bg-border-strong\",\n i > activeIndex && \"bg-border\"\n )}\n />\n ))}\n </div>\n );\n }\n\n return (\n <div {...shared} className={cn(\"flex items-center gap-2\", className)}>\n {steps.map((step, i) => (\n <div key={step} className=\"flex items-center gap-2\">\n <span\n aria-current={i === activeIndex ? \"step\" : undefined}\n className={cn(\n \"flex size-tile-sm items-center justify-center rounded-full text-xs font-medium\",\n i === activeIndex && \"bg-accent text-accent-fg\",\n i < activeIndex && \"bg-accent-soft text-accent\",\n i > activeIndex && \"bg-surface-hover text-text-muted\"\n )}\n >\n {i + 1}\n </span>\n {i < steps.length - 1 && <span className=\"h-px w-8 bg-border-strong\" />}\n </div>\n ))}\n </div>\n );\n}\n","import DOMPurify from \"dompurify\";\nimport type { Components } from \"react-markdown\";\nimport Markdown from \"react-markdown\";\nimport remarkGfm from \"remark-gfm\";\nimport { cn } from \"../utils/cn\";\n\n/**\n * Rendert tekst die óf markdown óf HTML kan zijn — één component voor alle\n * plekken waar door mensen of door een model geschreven tekst op het scherm komt.\n *\n * Waarom beide vormen: dezelfde velden worden door twee soorten schrijvers\n * gevuld. Een interne notitie komt als rich HTML uit de mention-composer, maar\n * als markdown uit een AI-tool of playbook. Wie er maar één van de twee rendert,\n * laat de andere als losse tekens staan — dat is waar `**5MB**` vandaan komt.\n *\n * - **HTML** → gesanitized met DOMPurify en als HTML gezet. Nooit ongefilterd:\n * de tekst kan van een model of van een externe provider komen.\n * - **markdown** → react-markdown met remark-gfm (tabellen, task lists,\n * doorhalen, autolinks). Die emit géén rauwe HTML, dus dat pad kan niets\n * injecteren.\n *\n * Beide takken worden bewust gelijk gestyled met semantische tokens, zodat een\n * notitie er hetzelfde uitziet of hij nu uit de composer of uit een playbook\n * komt. De HTML-tak heeft daarvoor descendant-classes nodig: Tailwind's preflight\n * haalt de browser-defaults van `ul`/`ol` weg, dus zonder deze regels verliest\n * gesanitizede HTML z'n opsommingstekens.\n */\n\nconst HTML_TAG = /<[a-z][\\s\\S]*>/i;\n\n/** Styling voor de HTML-tak; spiegelt de `components`-map hieronder. */\nconst HTML_PROSE = [\n \"[&_p]:my-1.5 [&_p:first-child]:mt-0 [&_p:last-child]:mb-0 [&_p]:leading-relaxed\",\n \"[&_a]:text-accent [&_a]:underline [&_a]:underline-offset-2\",\n \"[&_strong]:font-semibold [&_em]:italic\",\n \"[&_ul]:my-1.5 [&_ul]:list-disc [&_ul]:pl-5 [&_ol]:my-1.5 [&_ol]:list-decimal [&_ol]:pl-5\",\n \"[&_li]:leading-relaxed\",\n \"[&_h1]:mb-1 [&_h1]:mt-2 [&_h1]:font-semibold [&_h2]:mb-1 [&_h2]:mt-2 [&_h2]:font-semibold [&_h3]:mb-1 [&_h3]:mt-2 [&_h3]:font-semibold\",\n \"[&_blockquote]:my-1.5 [&_blockquote]:border-l-2 [&_blockquote]:border-border [&_blockquote]:pl-3 [&_blockquote]:text-text-muted\",\n \"[&_hr]:my-2 [&_hr]:border-border\",\n \"[&_pre]:my-1.5 [&_pre]:overflow-x-auto [&_pre]:rounded-md [&_pre]:bg-surface-sunk [&_pre]:p-2 [&_pre]:text-xs\",\n \"[&_code]:rounded-sm [&_code]:bg-surface-sunk [&_code]:px-1 [&_code]:py-0.5 [&_code]:font-mono [&_code]:text-xs\",\n \"[&_pre_code]:bg-transparent [&_pre_code]:p-0\",\n \"[&_table]:my-1.5 [&_table]:w-full [&_table]:border-collapse [&_table]:text-xs\",\n \"[&_th]:border [&_th]:border-border [&_th]:px-2 [&_th]:py-1 [&_th]:text-left [&_th]:font-semibold\",\n \"[&_td]:border [&_td]:border-border [&_td]:px-2 [&_td]:py-1\",\n].join(\" \");\n\nconst components: Components = {\n p: (props) => <p className=\"my-1.5 leading-relaxed first:mt-0 last:mb-0\" {...props} />,\n a: (props) => (\n <a className=\"text-accent underline underline-offset-2 hover:opacity-80\" target=\"_blank\" rel=\"noopener noreferrer\" {...props} />\n ),\n strong: (props) => <strong className=\"font-semibold\" {...props} />,\n em: (props) => <em className=\"italic\" {...props} />,\n ul: (props) => <ul className=\"my-1.5 list-disc space-y-0.5 pl-5\" {...props} />,\n ol: (props) => <ol className=\"my-1.5 list-decimal space-y-0.5 pl-5\" {...props} />,\n li: (props) => <li className=\"leading-relaxed\" {...props} />,\n h1: (props) => <h1 className=\"mb-1 mt-2 text-md font-semibold first:mt-0\" {...props} />,\n h2: (props) => <h2 className=\"mb-1 mt-2 text-base font-semibold first:mt-0\" {...props} />,\n h3: (props) => <h3 className=\"mb-1 mt-2 text-base font-semibold first:mt-0\" {...props} />,\n blockquote: (props) => (\n <blockquote className=\"my-1.5 border-l-2 border-border pl-3 text-text-muted\" {...props} />\n ),\n hr: (props) => <hr className=\"my-2 border-border\" {...props} />,\n pre: (props) => (\n <pre className=\"my-1.5 overflow-x-auto rounded-md bg-surface-sunk p-2 text-xs\" {...props} />\n ),\n code: ({ className, children, ...props }) => {\n const content = String(children ?? \"\");\n const isBlock = /language-/.test(className ?? \"\") || content.includes(\"\\n\");\n return isBlock ? (\n <code className=\"font-mono text-xs\" {...props}>{children}</code>\n ) : (\n <code className=\"rounded-sm bg-surface-sunk px-1 py-0.5 font-mono text-xs\" {...props}>{children}</code>\n );\n },\n table: (props) => (\n <div className=\"my-1.5 overflow-x-auto\">\n <table className=\"w-full border-collapse text-xs\" {...props} />\n </div>\n ),\n th: (props) => <th className=\"border border-border px-2 py-1 text-left font-semibold\" {...props} />,\n td: (props) => <td className=\"border border-border px-2 py-1\" {...props} />,\n};\n\nexport interface RichTextProps {\n /** Markdown of HTML; welke van de twee wordt gedetecteerd. */\n text: string | null | undefined;\n /** Extra classes op de wrapper (bv. `text-sm` of een line-clamp). */\n className?: string;\n /**\n * Forceer een tak in plaats van te detecteren. Alleen nodig als je zeker\n * weet wat je hebt en de heuristiek in de weg zit (bv. platte tekst die\n * toevallig op een tag lijkt).\n */\n as?: \"markdown\" | \"html\";\n}\n\n/** Veilig gerenderde markdown-of-HTML tekst. */\nexport function RichText({ text, className, as }: RichTextProps) {\n const src = text ?? \"\";\n const isHtml = as ? as === \"html\" : HTML_TAG.test(src);\n\n if (isHtml) {\n return (\n <div\n className={cn(\"break-words\", HTML_PROSE, className)}\n dangerouslySetInnerHTML={{ __html: DOMPurify.sanitize(src, { ADD_ATTR: [\"target\", \"rel\"] }) }}\n />\n );\n }\n\n return (\n <div className={cn(\"break-words\", className)}>\n <Markdown remarkPlugins={[remarkGfm]} components={components}>\n {src}\n </Markdown>\n </div>\n );\n}\n","import type { ArtifactBlock, ArtifactRuntime, ArtifactTone } from \"@opencxh/domain\";\nimport { cn } from \"../utils/cn\";\nimport { RichText } from \"./RichText\";\n\nexport interface ArtifactViewProps {\n blocks: ArtifactBlock[];\n /** Alles behalve `\"inert\"` wordt geweigerd. Zie de klassenoot hierboven. */\n runtime?: ArtifactRuntime;\n className?: string;\n}\n\n/** Statisch, want `text-${tone}-fg` genereert niets (Tailwind scant letterlijk). */\nconst KPI_TONE: Record<ArtifactTone, string> = {\n info: \"text-info-fg\",\n success: \"text-success-fg\",\n warning: \"text-warning-fg\",\n destructive: \"text-danger-fg\",\n};\n\nconst CALLOUT_TONE: Record<ArtifactTone, string> = {\n info: \"bg-info-soft border-info-border\",\n success: \"bg-success-soft border-success-border\",\n warning: \"bg-warning-soft border-warning-border\",\n destructive: \"bg-danger-soft border-danger-border\",\n};\n\n/** Eén tot vier tegels op een rij; ook statisch, om dezelfde reden. */\nconst KPI_COLUMNS: Record<number, string> = {\n 1: \"grid-cols-1\",\n 2: \"grid-cols-2\",\n 3: \"grid-cols-3\",\n 4: \"grid-cols-4\",\n};\n\nfunction Block({ block }: { block: ArtifactBlock }) {\n switch (block.type) {\n case \"heading\":\n if (block.level === 1) {\n return <h1 className=\"text-2xl font-semibold tracking-tight text-text\">{block.text}</h1>;\n }\n if (block.level === 2) {\n return <h2 className=\"pt-2 text-base font-semibold tracking-tight text-text\">{block.text}</h2>;\n }\n return <h3 className=\"pt-1 text-sm font-semibold text-text\">{block.text}</h3>;\n\n case \"paragraph\":\n return <RichText as=\"markdown\" text={block.text} className=\"text-sm text-text\" />;\n\n case \"quote\":\n return (\n <blockquote className=\"border-l-2 border-border pl-3.5\">\n <RichText as=\"markdown\" text={block.text} className=\"text-sm text-text-muted\" />\n </blockquote>\n );\n\n case \"code\":\n return (\n <pre className=\"overflow-x-auto rounded-lg bg-surface-sunk p-3 text-xs\">\n <code className=\"font-mono\">{block.text}</code>\n </pre>\n );\n\n case \"divider\":\n return <hr className=\"border-border-subtle\" />;\n\n case \"list\": {\n const List = block.style === \"numbered\" ? \"ol\" : \"ul\";\n return (\n <List\n className={cn(\n \"flex flex-col gap-2 pl-5 text-sm text-text\",\n block.style === \"numbered\" ? \"list-decimal\" : \"list-disc\",\n )}\n >\n {block.items.map((item, index) => (\n <li key={index} className=\"leading-relaxed marker:text-text-subtle\">\n {item.lead && <strong className=\"font-semibold\">{item.lead} </strong>}\n <RichText as=\"markdown\" text={item.text} className=\"inline\" />\n </li>\n ))}\n </List>\n );\n }\n\n case \"table\":\n return (\n <figure className=\"m-0\">\n {/* Brede tabellen scrollen in hun eigen doos; het document zelf mag\n nooit horizontaal schuiven. */}\n <div className=\"overflow-x-auto rounded-lg ring-1 ring-border\">\n <table className=\"w-full border-collapse text-sm\">\n <thead>\n <tr className=\"bg-surface-sunk\">\n {block.columns.map((column, index) => (\n <th\n key={index}\n className={cn(\n \"px-4 py-2.5 text-xs font-semibold text-text-muted\",\n column.align === \"right\" ? \"text-right\" : \"text-left\",\n )}\n >\n {column.label}\n </th>\n ))}\n </tr>\n </thead>\n <tbody>\n {block.rows.map((row, rowIndex) => (\n <tr key={rowIndex} className=\"border-t border-border-subtle\">\n {row.map((value, cellIndex) => (\n <td\n key={cellIndex}\n className={cn(\n \"px-4 py-2.5 tabular-nums text-text\",\n block.columns[cellIndex]?.align === \"right\" ? \"text-right\" : \"text-left\",\n )}\n >\n {value}\n </td>\n ))}\n </tr>\n ))}\n </tbody>\n </table>\n </div>\n {block.caption && (\n <figcaption className=\"pt-2 text-xs italic text-text-subtle\">{block.caption}</figcaption>\n )}\n </figure>\n );\n\n case \"kpi\":\n return (\n <div className={cn(\"grid gap-3\", KPI_COLUMNS[block.items.length] ?? \"grid-cols-4\")}>\n {block.items.map((item, index) => (\n <div key={index} className=\"rounded-lg bg-surface-sunk px-4 py-3.5\">\n <div\n className={cn(\n \"text-2xl font-semibold tracking-tight\",\n item.tone ? KPI_TONE[item.tone] : \"text-text\",\n )}\n >\n {item.value}\n </div>\n <div className=\"pt-0.5 text-xs text-text-muted\">{item.label}</div>\n </div>\n ))}\n </div>\n );\n\n case \"callout\":\n return (\n <div className={cn(\"rounded-lg border px-4 py-3\", CALLOUT_TONE[block.tone])}>\n {block.title && <div className=\"pb-0.5 text-sm font-semibold text-text\">{block.title}</div>}\n <RichText as=\"markdown\" text={block.text} className=\"text-sm text-text\" />\n </div>\n );\n\n default:\n // Onbekend blok: overslaan, niet crashen.\n return null;\n }\n}\n\nexport function ArtifactView({ blocks, runtime = \"inert\", className }: ArtifactViewProps) {\n if (runtime !== \"inert\") {\n return (\n <div className={cn(\"rounded-lg border border-warning-border bg-warning-soft px-4 py-3\", className)}>\n <div className=\"text-sm font-semibold text-text\">Deze versie kan hier niet getoond worden</div>\n <div className=\"pt-0.5 text-xs text-text-muted\">\n Hij is opgeslagen als <code className=\"font-mono\">{runtime}</code>, en deze weergave tekent\n alleen inerte inhoud.\n </div>\n </div>\n );\n }\n\n return (\n <article className={cn(\"flex flex-col gap-4\", className)}>\n {blocks.map((block, index) => (\n <Block key={block.block_id ?? index} block={block} />\n ))}\n </article>\n );\n}\n","import { Sparkles } from \"lucide-react\";\nimport React from \"react\";\nimport { cn } from \"../utils/cn\";\n\nexport interface AssistantCardProps extends Omit<React.HTMLAttributes<HTMLDivElement>, \"title\"> {\n /** Card heading (e.g. \"Briefing van je assistent\", \"Voorstel van de assistent\"). */\n title: React.ReactNode;\n /** Leading icon; defaults to the lucide Sparkles icon. */\n icon?: React.ReactNode;\n /** Optional action rendered on the header's right (e.g. a \"Gebruiken\" button). */\n action?: React.ReactNode;\n /** Body content. */\n children?: React.ReactNode;\n}\n\n/**\n * AI-assistant card shell — the tinted \"Briefing / Voorstel van de assistent\"\n * surface used on Mijn dag and in the Focus queue. Uses the `--assistant-*`\n * design-system tokens so the tint is mode-aware.\n *\n * @example\n * ```tsx\n * <AssistantCard title=\"Voorstel van de assistent\" action={<Button>Gebruiken</Button>}>\n * Marc wacht 12 min op WhatsApp — concept staat klaar.\n * </AssistantCard>\n * ```\n */\nexport function AssistantCard({ title, icon = <Sparkles className=\"size-icon-md\" aria-hidden />, action, children, className, ...props }: AssistantCardProps) {\n return (\n <div\n className={cn(\n \"flex flex-col gap-2 rounded-xl border p-4\",\n \"border-assistant-border bg-assistant-soft\",\n className,\n )}\n {...props}\n >\n <div className=\"flex items-center gap-2 text-assistant\">\n <span aria-hidden>{icon}</span>\n <span className=\"text-sm font-semibold\">{title}</span>\n {action && <span className=\"ml-auto\">{action}</span>}\n </div>\n {children && <div className=\"text-sm leading-relaxed text-text\">{children}</div>}\n </div>\n );\n}\n","import React from \"react\";\nimport { cn } from \"../utils/cn\";\nimport { identityPlateClass } from \"../utils/identity\";\n\n/**\n * Plate colour. `default` is the neutral disc used everywhere a monogram is just\n * an identity marker.\n *\n * `identity` derives the colour from `name`, so the same person or team is the\n * same colour on every surface — see {@link identityPlateClass}. Use it in a\n * list of many people; use `default` where there is only one plate on screen\n * and colour would carry no information.\n *\n * The other three are for a message thread, where the plate answers \"which side\n * is this from\" before you read a word: `in` is the other party, `out` is us\n * (ink, so it reads as ours in both themes) and `note` is an internal remark.\n * Each is a fill with its own foreground — a fill cannot borrow a colour from\n * the ramp, because the ramp does not change between light and dark.\n */\nexport type AvatarTone = \"default\" | \"identity\" | \"in\" | \"out\" | \"note\";\n\nconst toneClasses: Record<Exclude<AvatarTone, \"identity\">, string> = {\n default: \"bg-avatar text-avatar-fg\",\n in: \"bg-avatar-in text-avatar-in-fg\",\n out: \"bg-accent text-accent-fg\",\n note: \"bg-avatar-note text-avatar-note-fg\",\n};\n\nexport interface AvatarProps {\n /** Full name; used for the initials fallback and alt/title text */\n name?: string;\n /** Optional image URL; falls back to initials when absent or on load error */\n src?: string;\n /** Plate colour; see {@link AvatarTone}. */\n tone?: AvatarTone;\n /** Size preset */\n size?: \"xs\" | \"sm\" | \"md\" | \"lg\";\n /** Additional CSS classes */\n className?: string;\n /** Override the title attribute (defaults to `name`) */\n title?: string;\n}\n\nconst sizeClasses: Record<NonNullable<AvatarProps[\"size\"]>, string> = {\n xs: \"w-5 h-5 text-xs\",\n sm: \"w-6 h-6 text-xs\",\n md: \"w-7 h-7 text-base\",\n lg: \"w-9 h-9 text-sm\",\n};\n\nfunction initials(name?: string): string {\n if (!name) return \"?\";\n // Split op alles wat geen letter/cijfer is (spatie, @, ., -, _, …) zodat\n // adressen als \"mail-team@x.nl\" schone initialen geven (\"MT\"), niet \"M-\".\n const parts = name.trim().split(/[^\\p{L}\\p{N}]+/u).filter(Boolean);\n if (parts.length >= 2) return (parts[0][0] + parts[1][0]).toUpperCase();\n if (parts.length === 1) return parts[0].slice(0, 2).toUpperCase();\n return \"?\";\n}\n\n/**\n * Circular avatar: renders the photo when `src` is set (falling back to\n * initials on error), otherwise a monogram derived from `name`.\n */\nexport const Avatar: React.FC<AvatarProps> = ({ name, src, tone = \"default\", size = \"sm\", className, title }) => {\n const [errored, setErrored] = React.useState(false);\n const base = cn(\n // Its own token and not `surface-hover`: at 0.972 the plate was within a few\n // percent of every surface it sits on, so the monogram floated instead of\n // sitting in a disc.\n \"inline-flex items-center justify-center rounded-full overflow-hidden shrink-0 font-semibold select-none\",\n // `identity` is seeded on the name, so the same person keeps their colour\n // wherever they appear; the fixed tones stay as they were.\n tone === \"identity\" ? identityPlateClass(name) : toneClasses[tone],\n sizeClasses[size],\n className,\n );\n\n if (src && !errored) {\n return (\n <img\n src={src}\n alt={name ?? \"\"}\n title={title ?? name}\n className={cn(base, \"object-cover\")}\n onError={() => setErrored(true)}\n />\n );\n }\n\n return (\n <span className={base} title={title ?? name} aria-label={name}>\n {initials(name)}\n </span>\n );\n};\n","import React from \"react\";\nimport { cn } from \"../utils/cn\";\nimport { Avatar, type AvatarProps } from \"./Avatar\";\n\nexport interface AvatarStackPerson {\n id?: string;\n name?: string;\n src?: string;\n /** Owner / assignee — rendered with an accent ring */\n owner?: boolean;\n /** Whether this person has seen the item; unseen renders dimmed */\n seen?: boolean;\n}\n\nexport interface AvatarStackProps {\n people: AvatarStackPerson[];\n /** Max avatars to show before collapsing the rest into a \"+N\" chip */\n max?: number;\n size?: AvatarProps[\"size\"];\n className?: string;\n}\n\n// Panel-coloured ring so overlapping avatars stay visually separated; the\n// owner gets an extra accent halo on top of it.\nconst RING = \"ring-surface\";\nconst OWNER_RING = \"ring-surface-accent\";\n\n/**\n * Overlapping row of avatars with an optional \"+N\" overflow chip. Unseen\n * people are dimmed; the owner carries an accent ring.\n */\nexport const AvatarStack: React.FC<AvatarStackProps> = ({ people, max = 4, size = \"sm\", className }) => {\n if (people.length === 0) return null;\n const shown = people.slice(0, max);\n const overflow = people.length - shown.length;\n\n return (\n <span className={cn(\"inline-flex items-center\", className)}>\n {shown.map((p, i) => (\n <Avatar\n key={p.id ?? `${p.name}-${i}`}\n name={p.name}\n src={p.src}\n size={size}\n title={p.name ? (p.seen === false ? `${p.name} — nog niet gelezen` : p.name) : undefined}\n className={cn(\n i > 0 && \"-ml-2\",\n p.owner ? OWNER_RING : RING,\n p.seen === false && \"opacity-40\",\n )}\n />\n ))}\n {overflow > 0 && (\n <span\n className={cn(\n // Same fill as an Avatar plate, so the \"+3\" reads as one more disc\n // in the row rather than a gap at the end of it.\n \"inline-flex items-center justify-center rounded-full shrink-0 -ml-2 font-semibold bg-avatar text-avatar-fg\",\n size === \"xs\" ? \"w-5 h-5 text-xs\" : size === \"md\" ? \"w-7 h-7 text-xs\" : size === \"lg\" ? \"w-9 h-9 text-xs\" : \"w-6 h-6 text-xs\",\n RING,\n )}\n >\n +{overflow}\n </span>\n )}\n </span>\n );\n};\n","import React from \"react\";\nimport { cn } from \"../utils/cn\";\nimport { identityPlateClass } from \"../utils/identity\";\n\n/** Communication channel keys the redesign colour-codes. */\nexport type ChannelKey = \"mail\" | \"wa\" | \"chat\" | \"tel\" | \"note\";\n\nexport interface ChannelBadgeProps {\n /**\n * Channel — drives the colour. A known key uses that channel's tokens; any\n * other string (a provider that brought its own channel along) gets a stable\n * colour derived from the string itself, so ten custom channels stay ten\n * distinguishable colours instead of ten identical grey tiles.\n */\n channel?: ChannelKey | string;\n /** Glyph or short label inside the tile (e.g. an icon, or an initial). */\n children?: React.ReactNode;\n /** Tile size. */\n size?: \"sm\" | \"md\" | \"lg\";\n className?: string;\n title?: string;\n}\n\n/**\n * Channel key → semantic token pair. The keys are the redesign's shorthand\n * (`wa`, `tel`); the tokens spell the channel out (`whatsapp`, `phone`).\n * Written as whole class names so Tailwind can find them.\n */\nconst CH: Record<ChannelKey, { fg: string; bg: string }> = {\n mail: { fg: \"text-channel-mail-fg\", bg: \"bg-channel-mail-soft\" },\n wa: { fg: \"text-channel-whatsapp-fg\", bg: \"bg-channel-whatsapp-soft\" },\n chat: { fg: \"text-channel-chat-fg\", bg: \"bg-channel-chat-soft\" },\n tel: { fg: \"text-channel-phone-fg\", bg: \"bg-channel-phone-soft\" },\n note: { fg: \"text-channel-note-fg\", bg: \"bg-channel-note-soft\" },\n};\n\nconst sizes: Record<NonNullable<ChannelBadgeProps[\"size\"]>, string> = {\n sm: \"size-avatar-xs rounded-sm text-xs\",\n md: \"size-avatar-sm rounded-md text-xs\",\n lg: \"size-avatar-lg rounded-md text-base\",\n};\n\n/**\n * Coloured channel tile (the glyph-in-rounded-square used across inbox rows,\n * the focus queue, the attention list and Recent tabs). Colours come from the\n * `--color-channel-*` design-system tokens, so it is mode-aware.\n *\n * @example\n * ```tsx\n * <ChannelBadge channel=\"wa\">W</ChannelBadge>\n * <ChannelBadge channel=\"mail\" size=\"lg\"><MailIcon /></ChannelBadge>\n * ```\n */\nexport function ChannelBadge({ channel, children, size = \"md\", className, title }: ChannelBadgeProps) {\n const known = (channel as ChannelKey) in CH ? CH[channel as ChannelKey] : undefined;\n return (\n <span\n title={title}\n className={cn(\n \"inline-flex shrink-0 items-center justify-center font-bold\",\n sizes[size],\n // An undeclared channel used to collapse onto the neutral \"note\" tone,\n // which is also what a real internal note looks like. Deriving from the\n // key keeps it distinguishable and keeps `note` meaning `note`.\n known ? cn(known.fg, known.bg) : channel ? identityPlateClass(channel) : cn(CH.note.fg, CH.note.bg),\n className,\n )}\n >\n {children}\n </span>\n );\n}\n","import React, { useState } from 'react';\nimport { ImageOff } from \"lucide-react\";\nimport { Icon } from \"./Icon\";\nimport { cn } from '../utils/cn';\n\nexport interface ImageProps extends React.ImgHTMLAttributes<HTMLImageElement> {\n /** Image source URL */\n src: string;\n /** Alt text for accessibility */\n alt: string;\n /** Image size preset */\n size?: 'xs' | 'sm' | 'md' | 'lg' | 'xl' | 'full';\n /** Aspect ratio */\n aspectRatio?: 'square' | 'video' | 'portrait' | 'landscape' | 'auto';\n /** Border radius */\n radius?: 'none' | 'sm' | 'md' | 'lg' | 'xl' | 'full';\n /** Whether to show loading state */\n showLoading?: boolean;\n /** Whether to show error state */\n showError?: boolean;\n /** Fallback image URL */\n fallback?: string;\n /** Loading placeholder content */\n loadingContent?: React.ReactNode;\n /** Error placeholder content */\n errorContent?: React.ReactNode;\n /** Additional CSS classes */\n className?: string;\n}\n\n/**\n * Image component with loading states, error handling, and theme integration\n */\nexport const Image: React.FC<ImageProps> = ({\n src,\n alt,\n size = 'md',\n aspectRatio = 'auto',\n radius = 'md',\n showLoading = true,\n showError = true,\n fallback,\n loadingContent,\n errorContent,\n className,\n onLoad,\n onError,\n ...props\n}) => {\n const [isLoading, setIsLoading] = useState(true);\n const [hasError, setHasError] = useState(false);\n const [currentSrc, setCurrentSrc] = useState(src);\n\n const handleLoad = (event: React.SyntheticEvent<HTMLImageElement>) => {\n setIsLoading(false);\n setHasError(false);\n onLoad?.(event);\n };\n\n const handleError = (event: React.SyntheticEvent<HTMLImageElement>) => {\n setIsLoading(false);\n setHasError(true);\n \n // Try fallback if available and not already using it\n if (fallback && currentSrc !== fallback) {\n setCurrentSrc(fallback);\n setHasError(false);\n setIsLoading(true);\n return;\n }\n \n onError?.(event);\n };\n\n const containerClasses = cn(\n 'relative overflow-hidden bg-surface-hover',\n \n // Size variants\n {\n 'w-8 h-8': size === 'xs',\n 'w-12 h-12': size === 'sm',\n 'w-16 h-16': size === 'md',\n 'w-24 h-24': size === 'lg',\n 'w-32 h-32': size === 'xl',\n 'w-full h-full': size === 'full',\n },\n \n // Aspect ratio variants\n {\n 'aspect-square': aspectRatio === 'square',\n 'aspect-video': aspectRatio === 'video',\n 'aspect-portrait': aspectRatio === 'portrait',\n 'aspect-landscape': aspectRatio === 'landscape',\n },\n \n // Border radius variants\n {\n 'rounded-none': radius === 'none',\n 'rounded-sm': radius === 'sm',\n 'rounded-md': radius === 'md',\n 'rounded-lg': radius === 'lg',\n 'rounded-xl': radius === 'xl',\n 'rounded-full': radius === 'full',\n },\n \n className\n );\n\n const imageClasses = cn(\n 'w-full h-full object-cover transition-opacity duration-fast',\n {\n 'opacity-0': isLoading || hasError,\n 'opacity-100': !isLoading && !hasError,\n }\n );\n\n const placeholderClasses = cn(\n 'absolute inset-0 flex items-center justify-center',\n 'text-text-muted'\n );\n\n const defaultLoadingContent = (\n <div className=\"animate-pulse\">\n <div className=\"w-6 h-6 bg-surface-hover rounded\"></div>\n </div>\n );\n\n const defaultErrorContent = (\n <div className=\"text-center\">\n <Icon icon={ImageOff} size=\"lg\" className=\"mx-auto mb-1\" />\n <span className=\"text-xs\">Failed to load</span>\n </div>\n );\n\n return (\n <div className={containerClasses}>\n <img\n {...props}\n src={currentSrc}\n alt={alt}\n className={imageClasses}\n onLoad={handleLoad}\n onError={handleError}\n />\n \n {/* Loading state */}\n {isLoading && showLoading && (\n <div className={placeholderClasses}>\n {loadingContent || defaultLoadingContent}\n </div>\n )}\n \n {/* Error state */}\n {hasError && showError && (\n <div className={placeholderClasses}>\n {errorContent || defaultErrorContent}\n </div>\n )}\n </div>\n );\n}; ","import { ChevronRight, X } from \"lucide-react\";\nimport React from \"react\";\nimport { Checkbox } from \"../input/Checkbox\";\nimport { cn } from \"../utils/cn\";\n\nexport interface ListGroup {\n /** Group key — must match what `groupBy` returns */\n id: string;\n /** Header label; defaults to `id` */\n title?: string;\n /** Override the row count shown on the right */\n count?: number;\n /** Start collapsed (only with `collapsible`) */\n defaultCollapsed?: boolean;\n /**\n * `danger` tints the label and its count — for a section that is a problem\n * by definition (overdue, failed), where the rows themselves carry no\n * marker that the group is the bad one.\n */\n tone?: \"default\" | \"danger\" | \"muted\";\n}\n\nexport interface ListProps<T> {\n /** Rows to render */\n items: T[];\n /** Stable key per row */\n getRowKey?: (item: T, index: number) => string | number;\n /**\n * Row separation. `inset` gives each row a rounded hover plate held off the\n * edge instead of a rule — the treatment for a list of things you tick off\n * (tasks) rather than a table you scan across (the inbox).\n */\n variant?: \"plain\" | \"divided\" | \"bulleted\" | \"inset\";\n /** Leading slot — channel tile, avatar, status dot */\n leading?: (item: T, index: number) => React.ReactNode;\n /** Main content; defaults to `String(item)` */\n renderItem?: (item: T, index: number) => React.ReactNode;\n /** Trailing slot — timestamp, badge, counter */\n trailing?: (item: T, index: number) => React.ReactNode;\n /** Row click */\n onSelect?: (item: T, index: number) => void;\n /**\n * Fired when keyboard focus lands on a row. Lets a consumer mirror the\n * roving focus into its own \"active\" state (what a hand-rolled `useArrowNav`\n * used to provide) without owning the key handling.\n */\n onActiveIndexChange?: (index: number) => void;\n /** Highlighted row (accent wash) */\n isActive?: (item: T, index: number) => boolean;\n /** Bold + accent dot */\n unread?: (item: T, index: number) => boolean;\n /** Deprioritised noise (opacity) */\n dimmed?: (item: T, index: number) => boolean;\n\n /** Group rows under headers. Return the group id for each row. */\n groupBy?: (item: T, index: number) => string;\n /**\n * Group order and labels. Groups missing here are appended in order of first\n * appearance; groups listed here but empty are skipped.\n */\n groups?: ListGroup[];\n /** Header renderer; defaults to label + count */\n renderGroupHeader?: (group: ListGroup, items: T[]) => React.ReactNode;\n /** Headers stick to the top of the scroll container */\n stickyGroupHeaders?: boolean;\n /** Headers become a toggle that folds the group */\n collapsibleGroups?: boolean;\n /** Hide the count on the right of the header */\n hideGroupCount?: boolean;\n\n /** Checkbox column + bulk bar */\n selectable?: boolean;\n /** Selected rows (controlled) */\n selectedItems?: T[];\n /** Selection handler */\n onSelectionChange?: (selected: T[]) => void;\n /** Actions shown in the bulk bar when a selection exists */\n bulkActions?: React.ReactNode;\n\n /**\n * Column-label strip above the rows (\"Van · Gesprek · tijd\"), like the inbox.\n * Align it with the row by reusing the same widths as `renderItem`.\n */\n header?: React.ReactNode;\n /** Keep the column-label strip visible while scrolling */\n stickyHeader?: boolean;\n\n /** Wrap the list in a bordered container */\n bordered?: boolean;\n /** Empty state content */\n emptyContent?: React.ReactNode;\n /** Loading state */\n loading?: boolean;\n /** Number of skeleton rows while loading */\n loadingRows?: number;\n className?: string;\n \"aria-label\"?: string;\n}\n\n/**\n * One action in the bulk dock. Its own component rather than a `Button`\n * variant: the dock is an ink surface, so every ordinary button variant is a\n * light plate on a dark bar. Use it for the `bulkActions` slot.\n *\n * @example\n * ```tsx\n * bulkActions={<>\n * <ListBulkAction icon={<Icon icon={UserPlus} size=\"sm\" />} onClick={assign}>Toewijzen</ListBulkAction>\n * <ListBulkAction icon={<Icon icon={Archive} size=\"sm\" />} onClick={archive}>Archiveren</ListBulkAction>\n * </>}\n * ```\n */\nexport function ListBulkAction({\n icon,\n onClick,\n children,\n}: {\n icon?: React.ReactNode;\n onClick?: () => void;\n children: React.ReactNode;\n}) {\n return (\n <button\n type=\"button\"\n onClick={onClick}\n className={cn(\n \"inline-flex h-control-sm shrink-0 cursor-pointer items-center gap-1.5 rounded-md px-2.5\",\n \"text-sm font-medium whitespace-nowrap\",\n \"transition-colors duration-fast ease-out hover:bg-white/15\",\n \"focus-visible:outline-none focus-visible:focus-ring\"\n )}\n >\n {icon}\n {children}\n </button>\n );\n}\n\n/**\n * List — one row is one object you open, with content of varying length\n * (inbox conversations, notifications, search results). No column headers:\n * hierarchy lives inside the row.\n *\n * Use `Table` instead when you compare values between rows (sortable columns,\n * aligned amounts, select-all in a header).\n *\n * Grouped, like the inbox and task views:\n *\n * @example\n * ```tsx\n * <List\n * items={tasks}\n * getRowKey={(t) => t.id}\n * bordered\n * groupBy={(t) => t.bucket} // \"today\" | \"tomorrow\" | \"later\"\n * groups={[\n * { id: \"today\", title: \"Vandaag\" },\n * { id: \"tomorrow\", title: \"Morgen\" },\n * { id: \"later\", title: \"Later\" },\n * ]}\n * stickyGroupHeaders\n * collapsibleGroups\n * leading={(t) => <ChannelBadge channel={t.channel} size=\"sm\" />}\n * renderItem={(t) => <span className=\"truncate\">{t.title}</span>}\n * trailing={(t) => t.due}\n * unread={(t) => !t.read}\n * />\n * ```\n */\nexport function List<T>({\n items,\n getRowKey,\n variant = \"divided\",\n leading,\n renderItem,\n trailing,\n onSelect,\n onActiveIndexChange,\n isActive,\n unread,\n dimmed,\n groupBy,\n groups,\n renderGroupHeader,\n stickyGroupHeaders = false,\n collapsibleGroups = false,\n hideGroupCount = false,\n selectable = false,\n selectedItems = [],\n onSelectionChange,\n bulkActions,\n header,\n stickyHeader = false,\n bordered = false,\n emptyContent,\n loading = false,\n loadingRows = 4,\n className,\n \"aria-label\": ariaLabel,\n}: ListProps<T>) {\n const [collapsed, setCollapsed] = React.useState<Record<string, boolean>>(() =>\n Object.fromEntries(\n (groups ?? [])\n .filter((g) => g.defaultCollapsed)\n .map((g) => [g.id, true])\n )\n );\n\n const rootRef = React.useRef<HTMLDivElement>(null);\n\n /**\n * Roving focus across the rows. Rows are focusable in DOM order, so this walks\n * them directly rather than tracking an index — grouping and collapsing cannot\n * put it out of sync that way.\n */\n const handleKeyDown = (event: React.KeyboardEvent<HTMLDivElement>) => {\n const keys = [\"ArrowDown\", \"ArrowUp\", \"Home\", \"End\"];\n if (!keys.includes(event.key)) return;\n\n const rows = Array.from(\n rootRef.current?.querySelectorAll<HTMLLIElement>(\"li[data-list-row]\") ?? []\n );\n if (rows.length === 0) return;\n event.preventDefault();\n\n const current = rows.indexOf(document.activeElement as HTMLLIElement);\n const next =\n event.key === \"Home\" ? 0\n : event.key === \"End\" ? rows.length - 1\n : event.key === \"ArrowDown\" ? (current + 1) % rows.length\n : (current - 1 + rows.length) % rows.length;\n\n rows[next]?.focus();\n };\n\n const keyOf = (item: T, index: number) =>\n getRowKey ? getRowKey(item, index) : index;\n\n const isSelected = (item: T) => selectedItems.includes(item);\n\n const toggle = (item: T, checked: boolean) => {\n if (!onSelectionChange) return;\n onSelectionChange(\n checked ? [...selectedItems, item] : selectedItems.filter((i) => i !== item)\n );\n };\n\n const toggleAll = (checked: boolean) =>\n onSelectionChange?.(checked ? [...items] : []);\n\n const container = cn(\n \"flex flex-col\",\n // With a selection open the list has a dock at its foot. Sticky can only\n // park at the bottom of its own box, so on a list shorter than the window\n // the dock hung right under the last row instead of at the bottom of the\n // screen. Growing the box to the height of its parent puts it where it\n // belongs — and only while a selection exists, so an ordinary short list\n // keeps its natural height.\n selectable && selectedItems.length > 0 && \"min-h-full\",\n bordered && \"overflow-hidden rounded-lg border border-border-subtle\",\n className\n );\n\n if (loading) {\n return (\n <div className={container}>\n {Array.from({ length: loadingRows }).map((_, i) => (\n <div\n key={`skeleton-${i}`}\n className={cn(\n \"flex animate-pulse items-center gap-3 px-4 py-2\",\n variant === \"divided\" && i > 0 && \"border-t border-border-subtle\"\n )}\n >\n <span className=\"size-tile-sm shrink-0 rounded-md bg-surface-hover\" />\n <span className=\"h-3 w-30 shrink-0 rounded-sm bg-surface-hover\" />\n <span className=\"h-3 flex-1 rounded-sm bg-surface-hover\" />\n <span className=\"h-3 w-8 shrink-0 rounded-sm bg-surface-hover\" />\n </div>\n ))}\n </div>\n );\n }\n\n if (items.length === 0 && emptyContent) {\n return <div className={container}>{emptyContent}</div>;\n }\n\n const allSelected = items.length > 0 && selectedItems.length === items.length;\n const someSelected = selectedItems.length > 0 && !allSelected;\n\n // ---- rows, in one flat pass so `index` keeps pointing at the source item ----\n const renderRow = (item: T, index: number, firstInBlock: boolean) => {\n const active = isActive?.(item, index) ?? false;\n const isUnread = unread?.(item, index) ?? false;\n const isDimmed = dimmed?.(item, index) ?? false;\n const selected = selectable && isSelected(item);\n\n return (\n <li\n key={keyOf(item, index)}\n // A clickable row cannot be a <button>: it holds a checkbox and may hold\n // trailing actions, and buttons may not nest. Button semantics are put on\n // the row instead, so it is reachable, operable and announced correctly.\n {...(onSelect\n ? {\n role: \"button\" as const,\n tabIndex: 0,\n \"data-list-row\": \"\",\n \"aria-current\": active || undefined,\n onClick: () => onSelect(item, index),\n onFocus: () => onActiveIndexChange?.(index),\n onKeyDown: (event: React.KeyboardEvent<HTMLLIElement>) => {\n if (event.key !== \"Enter\" && event.key !== \" \") return;\n // Space scrolls the page by default.\n event.preventDefault();\n onSelect(item, index);\n },\n }\n : {})}\n className={cn(\n \"flex items-center gap-3 text-base\",\n \"transition-colors duration-fast ease-out\",\n variant === \"inset\" ? \"mx-2 rounded-lg px-3 py-2.5\" : \"px-5 py-2.5\",\n variant === \"divided\" && !firstInBlock && \"border-t border-border-subtle\",\n onSelect && \"cursor-pointer focus-visible:outline-none focus-visible:focus-ring\",\n // An unread row is tinted, not bolded: at five columns a bold row\n // shouts across all of them, while the tint marks the row and leaves\n // the consumer free to weight only the sender and the subject.\n active || selected\n ? \"bg-accent-soft text-text\"\n : isUnread\n ? cn(\"bg-surface-unread\", onSelect && \"hover:bg-surface-unread-hover\")\n : onSelect && \"hover:bg-surface-hover\",\n // Read rows stay at full opacity — fading them also fades the avatars\n // and team dots, which is exactly the identity you scan by. They read\n // as secondary through weight and text colour instead.\n isDimmed && \"text-text-muted\"\n )}\n >\n {selectable && (\n <span onClick={(e) => e.stopPropagation()}>\n <Checkbox\n checked={isSelected(item)}\n onChange={(e) => toggle(item, e.target.checked)}\n aria-label=\"Rij selecteren\"\n />\n </span>\n )}\n\n {variant === \"bulleted\" && (\n <span\n aria-hidden\n className=\"mt-2 size-1.5 shrink-0 self-start rounded-full bg-border-strong\"\n />\n )}\n\n {leading && <span className=\"shrink-0\">{leading(item, index)}</span>}\n\n <div className=\"flex min-w-0 flex-1 items-center gap-2\">\n {renderItem ? renderItem(item, index) : String(item)}\n </div>\n\n {trailing && (\n <span className=\"shrink-0 text-xs text-text-subtle\">\n {trailing(item, index)}\n </span>\n )}\n </li>\n );\n };\n\n const body = (() => {\n if (!groupBy) {\n return items.map((item, index) => renderRow(item, index, index === 0));\n }\n\n // group id -> [{ item, index }], first-appearance order\n const buckets = new Map<string, { item: T; index: number }[]>();\n items.forEach((item, index) => {\n const id = groupBy(item, index);\n if (!buckets.has(id)) buckets.set(id, []);\n buckets.get(id)!.push({ item, index });\n });\n\n const declared = groups ?? [];\n const order: ListGroup[] = [\n ...declared.filter((g) => buckets.has(g.id)),\n ...[...buckets.keys()]\n .filter((id) => !declared.some((g) => g.id === id))\n .map((id) => ({ id })),\n ];\n\n return order.flatMap((group, groupIndex) => {\n const rows = buckets.get(group.id) ?? [];\n const isCollapsed = collapsibleGroups && collapsed[group.id];\n const label = group.title ?? group.id;\n const count = group.count ?? rows.length;\n\n const header = (\n <li\n key={`group-${group.id}`}\n onClick={\n collapsibleGroups\n ? () =>\n setCollapsed((prev) => ({ ...prev, [group.id]: !prev[group.id] }))\n : undefined\n }\n className={cn(\n // A caption over its rows, not a band across the table: same\n // surface as the rows, no rules, and the count as a quiet pill.\n // The old grey uppercase strip read as a second column header.\n \"flex items-center gap-2.5 bg-surface px-5 pb-1.5 text-base font-semibold\",\n groupIndex > 0 ? \"pt-5\" : \"pt-3\",\n group.tone === \"danger\" ? \"text-danger-fg\"\n : group.tone === \"muted\" ? \"text-text-subtle\"\n : \"text-text\",\n stickyGroupHeaders && \"sticky z-10\",\n collapsibleGroups && \"cursor-pointer select-none\"\n )}\n aria-expanded={collapsibleGroups ? !isCollapsed : undefined}\n // the column strip is 28px tall, so grouped headers park underneath it\n style={stickyGroupHeaders ? { top: stickyHeader ? 28 : 0 } : undefined}\n >\n {renderGroupHeader ? (\n renderGroupHeader(group, rows.map((r) => r.item))\n ) : (\n <>\n {collapsibleGroups && (\n <ChevronRight\n aria-hidden\n className={cn(\n \"size-icon-md shrink-0 text-text-subtle transition-transform duration-fast ease-out\",\n !isCollapsed && \"rotate-90\"\n )}\n />\n )}\n <span>{label}</span>\n {!hideGroupCount && (\n <span\n className={cn(\n \"rounded-full px-2 text-xs font-normal tabular-nums\",\n group.tone === \"danger\"\n ? \"bg-danger-soft text-danger-fg\"\n : \"bg-surface-sunk text-text-subtle\"\n )}\n >\n {count}\n </span>\n )}\n </>\n )}\n </li>\n );\n\n if (isCollapsed) return [header];\n\n return [\n header,\n ...rows.map(({ item, index }, rowIndex) =>\n renderRow(item, index, rowIndex === 0)\n ),\n ];\n });\n })();\n\n return (\n <div ref={rootRef} className={container} onKeyDown={onSelect ? handleKeyDown : undefined}>\n {header && (\n <div\n className={cn(\n // h-row-sm keeps the strip exactly 28px, which is the offset the\n // sticky group headers park against.\n \"flex h-row-sm items-end gap-3 border-b border-border bg-surface px-5 pb-2\",\n \"text-xs font-semibold uppercase tracking-wider text-text-disabled\",\n stickyHeader && \"sticky top-0 z-20\"\n )}\n >\n {selectable && (\n <span className=\"flex items-center\">\n <Checkbox\n checked={allSelected}\n indeterminate={someSelected}\n onChange={(e) => toggleAll(e.target.checked)}\n aria-label=\"Alles selecteren\"\n />\n </span>\n )}\n {header}\n </div>\n )}\n\n <ul aria-label={ariaLabel} className=\"flex flex-col\">\n {body}\n </ul>\n\n {/* Bulk bar — a dock that floats over the rows rather than a strip that\n pushes them down, so acting on a selection never moves the rows you\n are selecting. Sticky, so it rides the bottom of the scroll area. */}\n {selectable && selectedItems.length > 0 && (\n <div className=\"pointer-events-none sticky bottom-0 z-10 flex justify-center px-5 pb-4\">\n <div className=\"pointer-events-auto flex items-center gap-1.5 rounded-lg bg-accent py-1.5 pl-3.5 pr-1.5 text-accent-fg shadow-overlay\">\n <span className=\"text-sm font-medium\">\n {selectedItems.length} geselecteerd\n </span>\n <span aria-hidden className=\"mx-1.5 h-4 w-px bg-current opacity-25\" />\n {bulkActions}\n <span aria-hidden className=\"mx-1.5 h-4 w-px bg-current opacity-25\" />\n <button\n type=\"button\"\n onClick={() => onSelectionChange?.([])}\n aria-label=\"Selectie wissen\"\n className=\"grid size-tile-md shrink-0 cursor-pointer place-items-center rounded-md transition-colors duration-fast ease-out hover:bg-white/15 focus-visible:outline-none focus-visible:focus-ring\"\n >\n <X className=\"size-icon-lg\" />\n </button>\n </div>\n </div>\n )}\n </div>\n );\n}\n","import React from \"react\";\nimport { cn } from \"../utils/cn\";\n\nexport interface MessageBubbleProps {\n /** Direction. `in` is received, `out` is sent by us. */\n side: \"in\" | \"out\";\n /**\n * Part of a run from the same sender. The bubble keeps its shape; callers use\n * this to drop the repeated header and avatar.\n */\n continued?: boolean;\n /**\n * `warning` for a message that is not settled yet, e.g. a pending draft.\n * `note` is the internal-note surface — amber, never customer-visible.\n */\n tone?: \"default\" | \"warning\" | \"note\";\n /**\n * Layout only — padding, flex behaviour, margins.\n *\n * Not width: the bubble caps its own, because `cn` is plain clsx with no\n * tailwind-merge, so a `max-w-*` passed here would not reliably beat the\n * default — both land in the class list and CSS order decides. A message\n * that runs the full width of the thread stops reading as a message.\n */\n className?: string;\n children: React.ReactNode;\n}\n\n/**\n * A single message in a conversation: chat, email and call transcript all use\n * the same shape.\n *\n * The corner facing the sender is tight (`rounded-sm`) and the other three are\n * `rounded-lg`, which is what makes direction readable without a tail. Sent\n * messages sit on `bg-bubble-out-soft`, a 4% ink wash — deliberately lighter than\n * `accent-soft`, which reads as heavy on every message you have ever sent.\n *\n * @example\n * ```tsx\n * <MessageBubble side=\"out\" className=\"max-w-bubble px-4 py-3\">\n * <Text>{body}</Text>\n * </MessageBubble>\n * ```\n */\nexport function MessageBubble({\n side,\n continued = false,\n tone = \"default\",\n className,\n children,\n}: MessageBubbleProps) {\n return (\n <div\n className={cn(\n // A bubble never spans the whole column; it narrows further from md,\n // where the thread itself is wide enough for the difference to matter.\n // No shadow: a bubble is an inner card, and inner cards separate\n // themselves with a fill. The shadow was doing the separating while both\n // sides were white.\n \"min-w-0 max-w-bubble md:max-w-bubble-md\",\n // No outline on an ordinary message: its fill already separates it from\n // the thread, and a border on every bubble turns a conversation into a\n // stack of boxes. The flagged tones keep theirs — there the outline is\n // the signal, not decoration.\n // tone === \"warning\" && \"border border-warning-border\",\n // tone === \"note\" && \"border border-note-border\",\n // The tight corner points back at the sender.\n side === \"out\" ? \"rounded-lg rounded-tr-sm\" : \"rounded-lg rounded-tl-sm\",\n // Sent is a pale blue, received the neutral sunk grey — the same pair the\n // full-width feed cards use, so a chat thread and a mail thread say\n // \"ours\" and \"theirs\" the same way. Both used to be white on white,\n // which left the corner radius as the only cue.\n tone === \"note\"\n ? \"bg-note-soft\"\n : side === \"out\"\n ? \"bg-bubble-out-soft\"\n : \"bg-surface-sunk\",\n continued && \"mt-1\",\n className\n )}\n >\n {children}\n </div>\n );\n}\n","import React from \"react\";\nimport { cn } from \"../utils/cn\";\n\nexport interface KpiCardProps extends React.HTMLAttributes<HTMLDivElement> {\n /** The big number / metric. */\n value: React.ReactNode;\n /** Caption under the value. */\n label: React.ReactNode;\n /** Tone — `urgent` tints the number + border, `success` tints the number. */\n tone?: \"default\" | \"urgent\" | \"success\";\n}\n\nconst valueTone: Record<NonNullable<KpiCardProps[\"tone\"]>, string> = {\n default: \"text-text\",\n urgent: \"text-danger-fg\",\n success: \"text-success-fg\",\n};\n\n/**\n * KPI / stat card (the Mijn dag metric row). Token-driven, mode-aware.\n *\n * @example\n * ```tsx\n * <KpiCard value={3} label=\"wachten op jou · gem. 1u12\" />\n * <KpiCard value={1} label=\"dreigt SLA te missen\" tone=\"urgent\" />\n * ```\n */\nexport function KpiCard({ value, label, tone = \"default\", className, ...props }: KpiCardProps) {\n return (\n <div className={cn(\"rounded-xl bg-editor px-4 py-3.5\", className)} {...props}>\n <div className={cn(\"text-2xl font-semibold\", valueTone[tone])}>{value}</div>\n <div className=\"pt-0.5 text-xs text-text-muted\">{label}</div>\n </div>\n );\n}\n","import { ChevronLeft, Pencil } from \"lucide-react\";\nimport React, { useEffect, useRef, useState } from \"react\";\nimport { Button, type ButtonProps } from \"../action/Button\";\nimport { SplitButton, type SplitButtonOption } from \"../action/SplitButton\";\nimport { cn } from \"../utils/cn\";\nimport { Icon } from \"./Icon\";\n\nexport interface PageHeaderAction {\n /** Action identifier */\n id: string;\n /** Action label */\n label: string;\n /** Action icon */\n icon?: React.ReactNode;\n /** Action handler */\n onClick: () => void;\n /** Action variant. Tracks Button, so the two cannot drift apart. */\n variant?: ButtonProps[\"variant\"];\n /** Whether action is disabled */\n disabled?: boolean;\n /** Dropdown options for split button */\n splitOptions?: SplitButtonOption[];\n /**\n * Render this action yourself instead of as a Button — a filter chip, a\n * segmented toggle, an avatar stack. Position follows the array, so put it\n * before the buttons to have it sit to their left. When set, every other\n * field except `id` is ignored.\n */\n render?: () => React.ReactNode;\n}\n\nexport interface PageHeaderProps {\n /**\n * `plain` sits directly on the page. `surface` is the app-bar treatment:\n * its own background, full-bleed, closed off with a bottom border.\n */\n surface?: boolean;\n /** Page title */\n title: string;\n /** Page subtitle/description. Sits beside the title. */\n subtitle?: string;\n /**\n * Meta line under the title — a contact, a channel, a timestamp. Distinct\n * from `subtitle`, which sits beside the title, and from `children`, which\n * is the full-width row at the bottom of the header.\n *\n * A string is kept to one line and ellipsised; a node is allowed to wrap, so\n * an inline row of properties survives a narrow window.\n */\n meta?: React.ReactNode;\n /** Breadcrumb items */\n breadcrumbs?: Array<{ label: string; href?: string }>;\n /** Action buttons */\n actions?: PageHeaderAction[];\n /** Additional content to render in the header */\n children?: React.ReactNode;\n /** Additional CSS classes */\n className?: string;\n /** Back button label */\n backLabel?: string;\n /** Back button handler */\n onBack?: () => void;\n /** Back button class name */\n backClassName?: string;\n /** Whether the title is editable */\n editable?: boolean;\n /** Callback when title is changed */\n onTitleChange?: (newTitle: string) => void;\n}\n\nexport const ChevronLeftIcon = () => <Icon icon={ChevronLeft} size=\"md\" color=\"current\" />;\n\n/**\n * PageHeader component for consistent page layouts with title, actions, and breadcrumbs\n */\nexport const PageHeader: React.FC<PageHeaderProps> = ({\n surface = false,\n title,\n subtitle,\n meta,\n actions = [],\n children,\n className,\n backLabel = \"Back\",\n backClassName,\n onBack,\n editable = false,\n onTitleChange,\n}) => {\n const [isEditing, setIsEditing] = useState(false);\n const [editValue, setEditValue] = useState(title);\n const inputRef = useRef<HTMLInputElement>(null);\n\n // Update editValue when title prop changes\n useEffect(() => {\n setEditValue(title);\n }, [title]);\n\n // Focus input when editing starts\n useEffect(() => {\n if (isEditing && inputRef.current) {\n inputRef.current.focus();\n inputRef.current.select();\n }\n }, [isEditing]);\n\n const handleTitleClick = () => {\n if (editable) {\n setIsEditing(true);\n }\n };\n\n const handleBlur = () => {\n setIsEditing(false);\n if (editValue.trim() !== \"\" && editValue !== title && onTitleChange) {\n onTitleChange(editValue.trim());\n } else {\n // Reset to original title if empty or unchanged\n setEditValue(title);\n }\n };\n\n const handleKeyDown = (e: React.KeyboardEvent<HTMLInputElement>) => {\n if (e.key === \"Enter\") {\n inputRef.current?.blur();\n } else if (e.key === \"Escape\") {\n setEditValue(title);\n setIsEditing(false);\n }\n };\n\n return (\n <div\n className={cn(\n \"px-5 pt-4 pb-2.5\",\n // Inside the content card the header shares the card's surface; the\n // rule is the only thing that still closes it off. `surface` therefore\n // only draws the rule — the background it used to paint is now the\n // card itself.\n surface && \"border-b border-border\",\n className\n )}\n >\n {/* Header Title + Actions */}\n <div className=\"flex flex-row sm:items-start sm:justify-between items-center gap-4\">\n {/* Title + Subtitle */}\n <div className=\"min-w-0 flex-1\">\n {/* Back sits beside the title block, not above the meta line, so the\n meta line starts under the title rather than under the button. */}\n <div className=\"flex items-start gap-4 text-text\">\n {onBack && (\n // Ghost: a framed box around a back chevron makes the way out of a\n // page look like the page's primary control.\n <Button variant=\"ghost\" onClick={onBack} leftIcon={<Icon icon={ChevronLeft} size=\"md\" />} iconOnly />\n )}\n\n <div className=\"min-w-0 flex-1\">\n {isEditing ? (\n <input\n ref={inputRef}\n type=\"text\"\n value={editValue}\n onChange={(e) => setEditValue(e.target.value)}\n onBlur={handleBlur}\n onKeyDown={handleKeyDown}\n className=\"text-1xl font-semibold bg-transparent border-b-1 border-border rounded-lg outline-none focus:border-none px-1 -mx-1 min-w-0 w-full\"\n />\n ) : (\n <div className=\"group flex items-baseline gap-2.5 min-w-0\">\n <h2\n onClick={handleTitleClick}\n className={cn(\n \"text-lg font-semibold tracking-title truncate\",\n editable && \"cursor-pointer\"\n )}\n title={editable ? \"Click to edit\" : undefined}\n >\n {title}\n </h2>\n {subtitle && (\n <span className=\"shrink-0 text-base text-text-muted truncate\">{subtitle}</span>\n )}\n {editable && (\n <Pencil\n size={15}\n onClick={handleTitleClick}\n className=\"shrink-0 cursor-pointer text-text-muted opacity-0 group-hover:opacity-100 transition-opacity\"\n />\n )}\n </div>\n )}\n\n {meta && (\n // A string meta is one line and ellipsises; a node may be a row\n // of controls (the interaction header's property line) that has\n // to be allowed to wrap — `truncate` would clip it to one line\n // and hide the last properties.\n <div\n className={cn(\n \"mt-1 min-w-0 text-sm text-text-subtle\",\n typeof meta === \"string\" && \"truncate\",\n )}\n >\n {meta}\n </div>\n )}\n </div>\n </div>\n </div>\n\n {/* Actions */}\n {actions.length > 0 && (\n <div className=\"flex flex-wrap sm:flex-nowrap gap-2 sm:gap-3\">\n {actions.map((action) =>\n action.render ? (\n <React.Fragment key={action.id}>{action.render()}</React.Fragment>\n ) : action.splitOptions && action.splitOptions.length > 0 ? (\n <SplitButton\n key={action.id}\n label={action.label}\n onClick={action.onClick}\n icon={action.icon}\n variant={action.variant === \"primary\" ? \"primary\" : \"outline\"}\n options={action.splitOptions}\n disabled={action.disabled}\n />\n ) : (\n <Button\n key={action.id}\n variant={action.variant ?? \"secondary\"}\n onClick={(e) => {\n e.stopPropagation();\n (e.target as HTMLButtonElement).blur();\n action.onClick();\n }}\n disabled={action.disabled}\n leftIcon={action.icon}\n >\n {action.label}\n </Button>\n )\n )}\n </div>\n )}\n </div>\n\n {/* Custom Slot Content */}\n {children && <div className=\"mt-4\">{children}</div>}\n </div>\n );\n};\n","import React, { type ReactNode } from \"react\";\nimport { ContentLoading, type ContentLoadingShape } from \"../feedback/ContentLoading\";\nimport { cn } from \"../utils/cn\";\nimport { PageHeader, type PageHeaderAction } from \"./PageHeader\";\n\n/**\n * The `md` gutter matches `PageHeader`'s own horizontal padding, so the table\n * or form below lines up with the title above it. The top value is small\n * because the header already supplies most of that gap (`pt-4 pb-2.5`).\n */\nconst paddingClasses = {\n none: \"\",\n sm: \"px-3 pb-3 pt-1\",\n md: \"px-5 pb-5 pt-1.5\",\n} as const;\n\nexport interface PageProps {\n /** Page title, rendered by `PageHeader`. */\n title: string;\n /** Short description beside the title. */\n subtitle?: string;\n /** Line under the title — a count, a record, a timestamp. */\n meta?: ReactNode;\n /** Toolbar actions, right-aligned in the header. */\n actions?: PageHeaderAction[];\n /** Renders the back chevron beside the title. */\n onBack?: () => void;\n /**\n * Lets the user rename the record from the header: the title becomes\n * clickable and grows a pencil beside it. `PageHeader` has had this for a\n * while; `Page` simply never forwarded it, so any page built on `Page` had to\n * put a rename somewhere else.\n */\n editable?: boolean;\n /** Called with the trimmed new title. Only fires when it actually changed. */\n onTitleChange?: (title: string) => void;\n /**\n * Draws the rule under the header. Off by default: inside the content card\n * the header shares the card's surface, and the card's own edge already ends\n * the page — a second line right under the title reads as a divider between\n * two panes that are not there.\n *\n * Turn it on for a header that has to stay legible over content moving\n * underneath it: a dense grid, a feed, anything where the first row would\n * otherwise scroll up flush against the title.\n */\n surface?: boolean;\n /** Full-width row at the bottom of the header — a filter strip, a tab bar. */\n headerContent?: ReactNode;\n /** Swaps the body for a skeleton. */\n loading?: boolean;\n /**\n * What the body is about to render, so the placeholder has the right shape.\n * Most app pages are a table; a detail page is usually a form.\n */\n loadingShape?: ContentLoadingShape;\n /**\n * Rendered instead of `children` when there is nothing to show — pass an\n * `EmptyState`. Ignored while `loading`, so an empty list does not flash its\n * \"nothing here\" message during the first fetch.\n */\n empty?: ReactNode;\n padding?: keyof typeof paddingClasses;\n /**\n * Whether the page owns its scroll. `true` (default) pins the header and\n * scrolls the body — the right behaviour for a table you page through.\n * Set `false` when the page is rendered inside something that already\n * scrolls and should flow with it.\n */\n scroll?: boolean;\n className?: string;\n contentClassName?: string;\n children?: ReactNode;\n}\n\n/**\n * One app page: the header, the content gutter, the scroll container, and the\n * loading and empty states.\n *\n * These four were re-invented per page — 24 times in `eylo-voip` alone, each\n * with its own gutter — which is how `p-4` there and `px-5` everywhere else\n * ended up side by side in the same product. Reach for this instead of pairing\n * a `PageHeader` with a padded `div`.\n *\n * Settings panels are the exception: they live inside the settings frame, which\n * draws its own title and scrolls itself, so they use `SettingsPage`.\n *\n * @example\n * ```tsx\n * <Page\n * title={t(\"interactions\")}\n * subtitle={t(\"interactions_description\")}\n * actions={[{ id: \"refresh\", label: t(\"refresh\"), onClick: reload }]}\n * loading={loading}\n * empty={!interactions.length && <EmptyState title={t(\"interaction_no_records_found\")} />}\n * >\n * <InteractionsTable interactions={interactions} />\n * </Page>\n * ```\n */\nexport const Page: React.FC<PageProps> = ({\n title,\n subtitle,\n meta,\n actions,\n onBack,\n editable,\n onTitleChange,\n surface = false,\n headerContent,\n loading = false,\n loadingShape = \"table\",\n empty,\n padding = \"md\",\n scroll = true,\n className,\n contentClassName,\n children,\n}) => {\n const body = loading ? (\n <ContentLoading variant=\"inline\" shape={loadingShape} />\n ) : empty ? (\n <div className=\"flex flex-col items-center justify-center py-12\">{empty}</div>\n ) : (\n children\n );\n\n return (\n <div\n className={cn(\n // `h-full` resolves against the shell's content card, which is the\n // element that scrolls today. Taking the scroll over here is what pins\n // the header; without `min-h-0` the body would grow past the card\n // instead of scrolling inside it.\n scroll ? \"flex h-full min-h-0 flex-col\" : \"flex flex-col\",\n className,\n )}\n >\n <PageHeader\n surface={surface}\n title={title}\n subtitle={subtitle}\n meta={meta}\n actions={actions}\n onBack={onBack}\n editable={editable}\n onTitleChange={onTitleChange}\n className={scroll ? \"shrink-0\" : undefined}\n >\n {headerContent}\n </PageHeader>\n\n <div\n className={cn(\n scroll && \"min-h-0 flex-1 overflow-y-auto\",\n paddingClasses[padding],\n contentClassName,\n )}\n >\n {body}\n </div>\n </div>\n );\n};\n","import React from \"react\";\nimport { cn } from \"../utils/cn\";\n\nexport interface SectionCaptionProps {\n /** Uppercase label. Short — this is a caption, not a heading. */\n label: string;\n /**\n * The right-hand slot: a count, a progress (\"1/3 done\") or a summary\n * (\"2 on a call · 1 away\"). A caption with nothing to its right is a caption\n * that could have been a heading.\n */\n meta?: string;\n /** Far right — a toggle or an icon button. Sits after `meta` when both are set. */\n action?: React.ReactNode;\n /** Layout only (margins, alignment). Not padding: see the note below. */\n className?: string;\n}\n\n/**\n * The section header over rounded plates and cards — the counterpart of the\n * sticky sunk band, which belongs to full-bleed divided rows.\n *\n * The top padding is generous and self-cancelling (`pt-7 first:pt-0`): a caption\n * is what separates two blocks in a scrolling panel, so it carries the gap\n * rather than the blocks around it, and the first one in a panel does not push\n * the content away from the panel header.\n *\n * `className` cannot override that padding — `cn` is plain clsx with no\n * tailwind-merge, so both classes would land in the list and CSS order would\n * decide. Use it for margins and alignment only.\n */\nexport const SectionCaption: React.FC<SectionCaptionProps> = ({ label, meta, action, className }) => (\n <div className={cn(\"flex items-center gap-2 px-1 pb-2 pt-7 first:pt-0\", className)}>\n <span className=\"shrink-0 text-2xs font-semibold uppercase tracking-label text-text-subtle\">{label}</span>\n {meta && (\n <span className=\"min-w-0 flex-1 truncate text-right text-xs tabular-nums text-text-subtle\">{meta}</span>\n )}\n {action && <span className=\"ml-auto shrink-0\">{action}</span>}\n </div>\n);\n","import React from \"react\";\nimport { cn } from \"../utils/cn\";\n\nexport interface SectionDividerProps {\n /** Centred label. Without one the divider is a plain rule. */\n label?: React.ReactNode;\n /** Right-aligned slot after the rule, e.g. a count or a status. */\n trailing?: React.ReactNode;\n /** Push the label to the start instead of centring it. */\n align?: \"center\" | \"start\";\n className?: string;\n}\n\n/**\n * A hairline that separates two runs of content, optionally naming the run that\n * follows: day separators in a feed, group headings in search results.\n *\n * @example\n * ```tsx\n * <SectionDivider label=\"Gisteren\" />\n * <SectionDivider label=\"Gesprekken\" align=\"start\" trailing={<Badge>12</Badge>} />\n * ```\n */\nexport function SectionDivider({ label, trailing, align = \"center\", className }: SectionDividerProps) {\n const rule = <span className=\"h-px flex-1 bg-border-subtle\" aria-hidden />;\n\n if (!label && !trailing) {\n return <div className={cn(\"flex items-center py-2\", className)}>{rule}</div>;\n }\n\n return (\n <div className={cn(\"flex items-center gap-3 py-2\", className)}>\n {align === \"center\" && rule}\n <span className=\"shrink-0 text-xs font-medium text-text-muted\">{label}</span>\n {rule}\n {trailing && <span className=\"shrink-0\">{trailing}</span>}\n </div>\n );\n}\n","import { ChevronLeft } from \"lucide-react\";\nimport React, {\n createContext,\n useContext,\n useEffect,\n useId,\n useMemo,\n useRef,\n useState,\n type ReactNode,\n} from \"react\";\nimport { Button } from \"../action/Button\";\nimport { ContentLoading, type ContentLoadingShape } from \"../feedback/ContentLoading\";\nimport { cn } from \"../utils/cn\";\nimport { Icon } from \"./Icon\";\nimport type { PageHeaderAction } from \"./PageHeader\";\nimport { PageToolbarActions } from \"./PageToolbar\";\n\n/**\n * What a panel adds to the frame it is rendered in: the record it drilled into,\n * and the way back out. The settings frame already draws the app breadcrumb and\n * the page title, so a panel that repeats them produces the double bar this\n * component exists to remove.\n */\nexport interface SettingsTrailEntry {\n /** Appended to the frame breadcrumb; usually the detail record's name. */\n title?: string;\n /** When set, the frame renders the back affordance and calls this. */\n onBack?: () => void;\n}\n\nexport interface SettingsFrameApi {\n /**\n * `ownerId` scopes the write to one panel instance. Stable across renders,\n * so it is safe to use as a hook dependency.\n */\n setTrail: (ownerId: string, entry: SettingsTrailEntry | null) => void;\n}\n\nconst SettingsFrameContext = createContext<SettingsFrameApi | null>(null);\n\n/**\n * Provided by the settings frame (the shell overlay), consumed by panels that\n * are federated remotes. Safe across the module-federation boundary because\n * React and `@opencxh/ui-kit` are both shared singletons — a second copy of\n * either would hand panels a different context object and the trail would\n * silently never arrive.\n */\nexport const SettingsFrameProvider = SettingsFrameContext.Provider;\n\nexport function useSettingsFrame(): SettingsFrameApi | null {\n return useContext(SettingsFrameContext);\n}\n\n/**\n * State half of the frame contract, for the host to own. Returns the current\n * trail plus the stable api to hand down through `SettingsFrameProvider`.\n */\nexport function useSettingsFrameHost() {\n const [state, setState] = useState<{ ownerId: string; entry: SettingsTrailEntry } | null>(null);\n\n const api = useMemo<SettingsFrameApi>(\n () => ({\n setTrail: (ownerId, entry) =>\n setState((prev) => {\n if (entry) return { ownerId, entry };\n // A panel that unmounts *after* its replacement has already mounted\n // must not wipe the replacement's trail. Only the current owner is\n // allowed to clear.\n return prev && prev.ownerId !== ownerId ? prev : null;\n }),\n }),\n []\n );\n\n return { trail: state?.entry ?? null, api };\n}\n\nconst paddingClasses = {\n none: \"\",\n sm: \"px-3 py-3\",\n // Matches the frame header's own horizontal padding, so content lines up\n // with the title above it.\n md: \"px-5 py-4\",\n} as const;\n\nexport interface SettingsPageProps {\n children: ReactNode;\n /**\n * Primary actions, right-aligned in the sticky footer — the Cancel/Save pair\n * of a form. Omit entirely on a read-only or list page and no footer renders.\n */\n actions?: PageHeaderAction[];\n /** Left-aligned footer actions, set apart from the primary pair (e.g. Delete). */\n secondaryActions?: PageHeaderAction[];\n /** Renders the back affordance in the frame header (or inline when unframed). */\n onBack?: () => void;\n backLabel?: string;\n /** The record's own name, appended to the frame breadcrumb. */\n title?: string;\n /** Swaps the body for a skeleton while keeping the footer in place. */\n loading?: boolean;\n /**\n * What the body is about to render. A settings panel is nearly always a form\n * or a table, and saying which keeps the placeholder from announcing a\n * heading and two paragraphs that never arrive.\n */\n loadingShape?: ContentLoadingShape;\n padding?: keyof typeof paddingClasses;\n className?: string;\n contentClassName?: string;\n}\n\n/**\n * The body of one settings panel. Owns the three things every panel used to\n * re-invent: the scroll container, the content padding, and where the actions\n * live. Title, description and breadcrumb belong to the frame — pass `title`\n * and `onBack` to extend them rather than drawing a second header here.\n */\nexport const SettingsPage: React.FC<SettingsPageProps> = ({\n children,\n actions = [],\n secondaryActions = [],\n onBack,\n backLabel = \"Back\",\n title,\n loading = false,\n loadingShape = \"form\",\n padding = \"md\",\n className,\n contentClassName,\n}) => {\n const frame = useSettingsFrame();\n const ownerId = useId();\n\n // The handler is re-created on every render of the panel; keeping it in a ref\n // means the effect below depends on *whether* there is a back action, not on\n // its identity — otherwise every render would re-publish the trail and the\n // resulting frame re-render would loop.\n const backRef = useRef(onBack);\n backRef.current = onBack;\n\n const hasBack = Boolean(onBack);\n\n useEffect(() => {\n if (!frame) return;\n if (!hasBack && !title) return;\n frame.setTrail(ownerId, {\n title,\n onBack: hasBack ? () => backRef.current?.() : undefined,\n });\n return () => frame.setTrail(ownerId, null);\n }, [frame, ownerId, title, hasBack]);\n\n const showFooter = actions.length > 0 || secondaryActions.length > 0;\n\n return (\n /**\n * `min-h-full` + a sticky footer, rather than a nested scroll container.\n * The frame already scrolls, and taking that over here would clip every\n * panel that has not been migrated yet. This way a short page still drops\n * its footer to the bottom, and a long one keeps it pinned while scrolling.\n */\n <div className={cn(\"flex min-h-full flex-col\", className)}>\n {/**\n * Unframed usage — the same panel opened as a modal or a plain route.\n * There is no frame to hand the title and the back action to, so this\n * draws them itself. Without this the record's name simply disappears\n * outside the settings overlay.\n */}\n {!frame && (hasBack || title) && (\n <div className=\"flex shrink-0 items-center gap-2 px-5 pt-4\">\n {hasBack && (\n <Button\n variant=\"ghost\"\n onClick={() => backRef.current?.()}\n aria-label={backLabel}\n leftIcon={<Icon icon={ChevronLeft} size=\"sm\" />}\n iconOnly\n />\n )}\n {title && (\n <h2 className=\"min-w-0 truncate text-md font-semibold tracking-title text-text\">\n {title}\n </h2>\n )}\n </div>\n )}\n\n <div className={cn(\"flex-1\", paddingClasses[padding], contentClassName)}>\n {loading ? <ContentLoading variant=\"inline\" shape={loadingShape} /> : children}\n </div>\n\n {showFooter && (\n <div className=\"sticky bottom-0 z-10 flex shrink-0 items-center gap-2 border-t border-border bg-surface px-5 py-3\">\n {secondaryActions.length > 0 && (\n <PageToolbarActions actions={secondaryActions} defaultVariant=\"ghost\" />\n )}\n {actions.length > 0 && (\n <PageToolbarActions actions={actions} className=\"ml-auto\" />\n )}\n </div>\n )}\n </div>\n );\n};\n","import React from \"react\";\nimport { cn } from \"../utils/cn\";\nimport { Icon } from \"./Icon\";\n\nexport interface SettingsRowProps {\n /** What the setting is called. */\n label: React.ReactNode;\n /** One line on what it does or what turning it on means. */\n description?: React.ReactNode;\n /** The control itself — a `Switch`, `Select`, `Button`… */\n control: React.ReactNode;\n /**\n * Draw the row as a bordered pill. Use it for a flat list of independent\n * toggles; leave it off inside a `SettingsSection`, which already groups.\n */\n bordered?: boolean;\n disabled?: boolean;\n className?: string;\n}\n\n/**\n * One setting: label (+ description) on the left, its control on the right.\n *\n * @example\n * ```tsx\n * <SettingsRow\n * label=\"Agenda synchroniseren\"\n * description=\"Afspraken uit dit account verschijnen in je agenda.\"\n * control={<Switch checked={on} onChange={setOn} aria-label=\"Agenda synchroniseren\" />}\n * />\n * ```\n */\nexport function SettingsRow({\n label,\n description,\n control,\n bordered = false,\n disabled = false,\n className,\n}: SettingsRowProps) {\n return (\n <div\n className={cn(\n \"flex items-center justify-between gap-4 py-2\",\n bordered && \"rounded-lg border border-border px-3\",\n disabled && \"opacity-50\",\n className\n )}\n >\n <div className=\"min-w-0\">\n <div className=\"text-sm text-text\">{label}</div>\n {description && (\n <div className=\"text-xs text-text-muted\">{description}</div>\n )}\n </div>\n <div className=\"shrink-0\">{control}</div>\n </div>\n );\n}\n\nexport interface SettingsSectionProps {\n /** Lucide icon component, rendered in the section heading. */\n icon?: React.ComponentType<Record<string, unknown>>;\n title: React.ReactNode;\n description?: React.ReactNode;\n /** Right-aligned slot in the heading, e.g. a \"Reset\" button. */\n actions?: React.ReactNode;\n children: React.ReactNode;\n className?: string;\n}\n\n/**\n * A titled group of `SettingsRow`s. The body is indented to line up under the\n * title text rather than the icon.\n */\nexport function SettingsSection({\n icon,\n title,\n description,\n actions,\n children,\n className,\n}: SettingsSectionProps) {\n return (\n <section className={cn(\"flex flex-col gap-2\", className)}>\n <div className=\"flex items-start gap-2\">\n {icon && <Icon icon={icon} size=\"md\" color=\"secondary\" className=\"mt-0.5\" />}\n <div className=\"min-w-0 flex-1\">\n <h3 className=\"text-sm font-semibold text-text\">{title}</h3>\n {description && (\n <p className=\"text-xs text-text-muted\">{description}</p>\n )}\n </div>\n {actions && <div className=\"shrink-0\">{actions}</div>}\n </div>\n <div className={cn(\"flex flex-col\", icon && \"pl-6\")}>{children}</div>\n </section>\n );\n}\n","import React from \"react\";\nimport { ArrowUpRight } from \"lucide-react\";\nimport { cn } from \"../utils/cn\";\nimport { Icon } from \"./Icon\";\n\nexport interface SourceChipProps {\n /** Label — the linked conversation subject. */\n label: React.ReactNode;\n /** Optional leading dot colour (a `--color-cat-*` or channel CSS var). */\n dotColor?: string;\n /** Click opens the linked conversation. */\n onClick?: () => void;\n className?: string;\n}\n\n/**\n * Source-conversation chip — the \"open brongesprek / gekoppeld gesprek ↗\" pill\n * that links a task or focus item back to its conversation.\n *\n * @example\n * ```tsx\n * <SourceChip label=\"Vraag over factuur maart\" dotColor=\"var(--color-cat-2)\" onClick={openThread} />\n * ```\n */\nexport function SourceChip({ label, dotColor, onClick, className }: SourceChipProps) {\n return (\n <button\n type=\"button\"\n onClick={onClick}\n className={cn(\n \"inline-flex max-w-full items-center gap-1.5 rounded-full bg-surface-sunk px-2.5 py-1 text-xs text-text-muted transition-colors duration-fast ease-out hover:bg-surface-hover hover:text-text\",\n className,\n )}\n >\n {dotColor && (\n <span className=\"h-1.5 w-1.5 shrink-0 rounded-full\" style={{ backgroundColor: dotColor }} aria-hidden />\n )}\n <span className=\"min-w-0 truncate\">{label}</span>\n <Icon icon={ArrowUpRight} size=\"xs\" className=\"opacity-70\" />\n </button>\n );\n}\n","import React from \"react\";\nimport { Badge, type BadgeProps } from \"../feedback/Badge\";\nimport type { TableColumn } from \"./Table\";\n\n/**\n * Column builders for the three things table configs kept getting wrong, each\n * in the same way across apps: a state rendered as prose, a stored code shown\n * raw, and an id shown instead of the name it points at.\n *\n * They all keep the *label* in `accessor` and render only the decoration in\n * `cell`, because `Table` searches and sorts on the accessor value. Putting the\n * readable text there means a search for \"Active\" or for a team's name matches\n * what the row actually shows — which is exactly what a raw `enabled` boolean\n * or a bare `teamId` used to break.\n */\n\nexport interface BadgeColumnConfig<T, V = unknown> {\n id: string;\n header: string;\n accessor: (row: T) => V;\n /** The text in the badge — and the text this column is searched on. */\n label: (value: V, row: T) => string;\n /** Defaults to `default`; give states their own tone (success/error/…). */\n tone?: (value: V, row: T) => BadgeProps[\"variant\"];\n /** Return false to render nothing at all for this row. */\n visible?: (value: V, row: T) => boolean;\n width?: string | number;\n sortable?: boolean;\n align?: TableColumn<T>[\"align\"];\n}\n\n/** A value that is a state rather than prose — render it as a pill. */\nexport function badgeColumn<T, V = unknown>(\n config: BadgeColumnConfig<T, V>\n): TableColumn<T> {\n const { id, header, accessor, label, tone, visible, width, sortable, align } = config;\n return {\n id,\n header,\n accessor: (row: T) => label(accessor(row), row),\n cell: (_value: unknown, row: T) => {\n const raw = accessor(row);\n if (visible && !visible(raw, row)) return null;\n return (\n <Badge variant={tone ? tone(raw, row) : \"default\"} size=\"sm\">\n {label(raw, row)}\n </Badge>\n );\n },\n width,\n sortable,\n align,\n };\n}\n\nexport interface BooleanBadgeColumnConfig<T> {\n id: string;\n header: string;\n accessor: (row: T) => boolean | undefined;\n onLabel: string;\n offLabel: string;\n /** Defaults to success/secondary — on reads as healthy, off as merely quiet. */\n onTone?: BadgeProps[\"variant\"];\n offTone?: BadgeProps[\"variant\"];\n width?: string | number;\n sortable?: boolean;\n}\n\n/** The on/off case of `badgeColumn`, which is most of them. */\nexport function booleanBadgeColumn<T>(\n config: BooleanBadgeColumnConfig<T>\n): TableColumn<T> {\n const {\n id, header, accessor, onLabel, offLabel,\n onTone = \"success\", offTone = \"secondary\", width, sortable,\n } = config;\n\n return badgeColumn<T, boolean>({\n id,\n header,\n accessor: (row) => !!accessor(row),\n label: (on) => (on ? onLabel : offLabel),\n tone: (on) => (on ? onTone : offTone),\n width,\n sortable,\n });\n}\n\nexport interface LabelsColumnConfig<T> {\n id: string;\n header: string;\n /** One code, a list of them, or nothing. */\n accessor: (row: T) => string | string[] | undefined | null;\n /**\n * Code to readable text. Return `undefined` to fall back to the code itself,\n * so an unknown value still shows something instead of vanishing.\n */\n label: (code: string) => string | undefined;\n /** Shown when there is nothing at all. Defaults to an em dash. */\n empty?: string;\n separator?: string;\n width?: string | number;\n searchable?: boolean;\n sortable?: boolean;\n}\n\n/**\n * Stored codes rendered as the words the user picked them by. Covers both\n * localising an enum (`interactions:created` → \"Interaction created\") and\n * resolving a foreign key (a `teamId` → that team's name — pass a lookup as\n * `label`), because from the table's side those are the same problem.\n */\nexport function labelsColumn<T>(config: LabelsColumnConfig<T>): TableColumn<T> {\n const {\n id, header, accessor, label, empty = \"—\", separator = \", \",\n width, searchable, sortable,\n } = config;\n\n return {\n id,\n header,\n accessor: (row: T) => {\n const raw = accessor(row);\n const codes = raw == null ? [] : Array.isArray(raw) ? raw : [raw];\n const labelled = codes.filter(Boolean).map((code) => label(code) ?? code);\n return labelled.length ? labelled.join(separator) : empty;\n },\n width,\n searchable,\n sortable,\n };\n}\n","import React, { useCallback } from \"react\";\nimport { Text } from \"../typography/Text\";\nimport { cn } from \"../utils/cn\";\n\nexport type ViewFieldType =\n | \"text\"\n | \"email\"\n | \"password\"\n | \"number\"\n | \"tel\"\n | \"url\"\n | \"textarea\"\n | \"select\"\n | \"checkbox\"\n | \"radio\"\n | \"date\"\n | \"custom\"\n | \"array\";\n\ntype NestedKeys<T> = {\n [K in keyof T]: T[K] extends object\n ? `${K & string}.${NestedKeys<T[K]>}`\n : K & string;\n}[keyof T];\n\nfunction getValueByPath<T>(obj: T, path: string): unknown {\n return path\n .split(\".\")\n .reduce(\n (acc, key) =>\n acc && typeof acc === \"object\" && key in acc\n ? (acc as any)[key]\n : undefined,\n obj\n );\n}\n\nexport interface ViewGroupItem<T = any> {\n /** Field name (key in data) */\n name: NestedKeys<T>;\n /** Field label */\n label: string;\n /** Field type */\n type: ViewFieldType;\n /** Field width (CSS width value or grid columns) */\n width?: string | number;\n /** Options for select/radio/checkbox types */\n options?: Array<{\n value: string | number;\n label: string;\n }>;\n /** Conditional function to show/hide field */\n conditional?: (data: T) => boolean;\n /** Whether field is hidden */\n hidden?: boolean;\n /** Custom component renderer */\n customComponent?: (props: { value: any }) => React.ReactNode;\n /** Format function for display value */\n format?: (value: any, data: T) => string | React.ReactNode;\n\n /** For 'array' type, defines the fields for each item in the array */\n arrayFields?: ViewGroupItem<any>[];\n}\n\nexport interface ViewGroup<T = any> {\n /** Group identifier */\n id: string;\n /** Group title */\n title: string;\n /** Group description */\n description?: string;\n /** Group items */\n items: ViewGroupItem<T>[];\n /** Conditional function to show/hide group */\n conditional?: (data: T) => boolean;\n /** Group layout */\n layout?: \"grid\" | \"flex\";\n /** Number of columns for grid layout */\n columns?: number;\n /** Additional CSS classes */\n className?: string;\n}\n\nexport interface ViewProps<T = Record<string, any>> {\n /** View groups */\n groups: ViewGroup<T>[];\n /** Data to display */\n data: T;\n /** View size */\n size?: \"sm\" | \"md\" | \"lg\" | \"full\";\n /** Additional CSS classes */\n className?: string;\n}\n\n/**\n * Generic View component with groups and conditional rendering\n * Displays data in a read-only format matching the Form component layout\n */\nexport const View = <T extends Record<string, any>>({\n groups,\n data,\n size = \"md\",\n className,\n}: ViewProps<T>) => {\n // Format date for display\n const formatDate = (value: any): string => {\n if (!value) return \"-\";\n try {\n const date = new Date(value);\n return date.toLocaleDateString(\"nl-NL\", {\n year: \"numeric\",\n month: \"long\",\n day: \"numeric\",\n });\n } catch {\n return String(value);\n }\n };\n\n // Format checkbox value\n const formatCheckbox = (value: any): string => {\n return value ? \"Ja\" : \"Nee\";\n };\n\n // Get display value for select/radio options\n const getOptionLabel = (\n value: any,\n options?: Array<{ value: string | number; label: string }>\n ): string => {\n if (!options) return String(value || \"-\");\n const option = options.find((opt) => opt.value === value);\n return option ? option.label : String(value || \"-\");\n };\n\n // Render a single field\n const renderField = useCallback(\n (item: ViewGroupItem<T>) => {\n const value = getValueByPath(data, item.name as string);\n\n // Handle array type\n if (item.type === \"array\") {\n const arrayValue = value as any[] | undefined;\n if (!arrayValue || arrayValue.length === 0) {\n return (\n <Text\n variant=\"body\"\n size=\"sm\"\n className=\"text-text-muted\"\n >\n Geen items\n </Text>\n );\n }\n\n return (\n <div className=\"space-y-3\">\n {arrayValue.map((row, index) => (\n <div\n key={index}\n className=\"p-4 border border-border rounded-xl space-y-3\"\n >\n <div className=\"flex items-center justify-between\">\n <Text\n variant=\"label\"\n size=\"sm\"\n weight=\"medium\"\n className=\"text-text-muted\"\n >\n {item.label} {index + 1}\n </Text>\n </div>\n <div className=\"grid grid-cols-1 sm:grid-cols-2 gap-3\">\n {item.arrayFields?.map((subField) => {\n const subValue = row?.[subField.name];\n let displayValue: React.ReactNode = \"-\";\n\n switch (subField.type) {\n case \"text\":\n case \"email\":\n case \"number\":\n case \"tel\":\n case \"url\":\n case \"textarea\":\n displayValue = subValue || \"-\";\n break;\n case \"select\":\n case \"radio\":\n displayValue = getOptionLabel(\n subValue,\n subField.options\n );\n break;\n case \"checkbox\":\n displayValue = formatCheckbox(subValue);\n break;\n case \"date\":\n displayValue = formatDate(subValue);\n break;\n case \"custom\":\n displayValue = subField.customComponent?.({\n value: subValue,\n });\n break;\n default:\n displayValue = String(subValue || \"-\");\n }\n\n if (subField.format) {\n displayValue = subField.format(subValue, row);\n }\n\n return (\n <div key={subField.name as string} className=\"space-y-1\">\n <Text\n variant=\"label\"\n size=\"xs\"\n className=\"text-text-muted\"\n >\n {subField.label}\n </Text>\n <Text\n variant=\"body\"\n size=\"sm\"\n className=\"text-text\"\n >\n {displayValue}\n </Text>\n </div>\n );\n })}\n </div>\n </div>\n ))}\n </div>\n );\n }\n\n // Handle custom component\n if (item.type === \"custom\" && item.customComponent) {\n return item.customComponent({ value });\n }\n\n // Handle format function\n if (item.format) {\n const formatted = item.format(value, data);\n return (\n <Text\n variant=\"body\"\n size=\"sm\"\n className=\"text-text\"\n >\n {formatted}\n </Text>\n );\n }\n\n // Default rendering based on type\n let displayValue: React.ReactNode = \"-\";\n\n switch (item.type) {\n case \"text\":\n case \"email\":\n case \"password\":\n case \"number\":\n case \"tel\":\n case \"url\":\n displayValue = value ? String(value) : \"-\";\n break;\n\n case \"textarea\":\n displayValue = value ? (\n <div className=\"whitespace-pre-wrap\">{String(value || \"-\")}</div>\n ) : (\n \"-\"\n );\n break;\n\n case \"select\":\n case \"radio\":\n displayValue = getOptionLabel(value, item.options);\n break;\n\n case \"checkbox\":\n displayValue = formatCheckbox(value);\n break;\n\n case \"date\":\n displayValue = formatDate(value);\n break;\n\n default:\n displayValue = value ? String(value) : \"-\";\n }\n\n return (\n <Text\n variant=\"body\"\n size=\"sm\"\n className=\"text-text\"\n >\n {displayValue}\n </Text>\n );\n },\n [data]\n );\n\n // Render view group\n const renderGroup = useCallback(\n (group: ViewGroup<T>) => {\n // Check group conditional\n if (group.conditional && !group.conditional(data)) {\n return null;\n }\n\n const visibleItems = group.items.filter((item) => {\n if (item.hidden) return false;\n if (item.conditional && !item.conditional(data)) return false;\n return true;\n });\n\n if (visibleItems.length === 0) return null;\n\n const groupClasses = cn(\n \"space-y-4\",\n {\n \"grid gap-4\": group.layout === \"grid\",\n \"flex flex-wrap gap-4\": group.layout === \"flex\",\n },\n group.layout === \"grid\" && {\n \"grid-cols-1\": !group.columns || group.columns === 1,\n \"grid-cols-2\": group.columns === 2,\n \"grid-cols-3\": group.columns === 3,\n \"grid-cols-4\": group.columns === 4,\n },\n group.className\n );\n\n return (\n <div\n key={group.id}\n className=\"grid grid-cols-1 md:grid-cols-3 gap-8 p-6 border border-border rounded-xl\"\n >\n {/* Group Header */}\n <div className=\"md:col-span-1\">\n <Text\n variant=\"label\"\n size=\"lg\"\n weight=\"semibold\"\n className=\"text-text\"\n >\n {group.title}\n </Text>\n {group.description && (\n <Text\n variant=\"body\"\n size=\"sm\"\n className=\"text-text-muted mt-1\"\n >\n {group.description}\n </Text>\n )}\n </div>\n\n {/* Group Items */}\n <div className=\"md:col-span-2\">\n <div className={groupClasses}>\n {visibleItems.map((item) => {\n return (\n <div\n key={item.name as string}\n className=\"space-y-1\"\n // Inline, not `w-[…]`/`col-span-…`: those are built at runtime,\n // so Tailwind never sees them and `width` silently did nothing.\n // Same fix Form.tsx already carries.\n style={{\n width: typeof item.width === \"string\" ? item.width : undefined,\n gridColumn:\n typeof item.width === \"number\"\n ? `span ${item.width} / span ${item.width}`\n : undefined,\n }}\n >\n {/* Field Label */}\n {item.type !== \"custom\" && (\n <Text\n variant=\"label\"\n size=\"sm\"\n className=\"font-medium text-text-muted\"\n >\n {item.label}\n </Text>\n )}\n\n {/* Field Value */}\n {renderField(item)}\n </div>\n );\n })}\n </div>\n </div>\n </div>\n );\n },\n [data, renderField]\n );\n\n const viewClasses = cn(\n \"space-y-6\",\n {\n \"max-w-md\": size === \"sm\",\n \"max-w-2xl\": size === \"md\",\n \"max-w-4xl\": size === \"lg\",\n \"max-w-full\": size === \"full\",\n },\n className\n );\n\n return (\n <div className={viewClasses}>\n {/* View Groups */}\n <div className=\"space-y-8\">{groups.map(renderGroup)}</div>\n </div>\n );\n};\n","import React from \"react\";\nimport { ContentLoading } from \"../feedback/ContentLoading\";\nimport { cn } from \"../utils/cn\";\n\nexport interface MenuItemAction {\n /** Icoon aan de rechterkant van de rij. */\n icon: React.ReactNode;\n /** Verplicht: aria-label + tooltip, het is een icon-only knop. */\n label: string;\n onClick: () => void;\n /** \"hover\" (default) = alleen zichtbaar bij hover/focus, \"always\" = altijd. */\n visibility?: \"hover\" | \"always\";\n}\n\nexport interface MenuItem {\n icon?: React.ReactNode;\n label: string;\n count?: number;\n /**\n * Optionele actie rechts op de rij — verwijderen, pinnen, dempen. Navigeert\n * niet: de knop stopt propagatie en roept alleen zijn eigen onClick aan.\n */\n action?: MenuItemAction;\n children?: MenuItem[];\n path?: string;\n /**\n * @deprecated Groepen klappen niet meer in — een sectie met children rendert\n * als kop met zijn items eronder. Blijft bestaan zodat bestaande call-sites\n * blijven compileren; de waarde wordt genegeerd.\n */\n defaultCollapsed?: boolean;\n}\n\ninterface SidebarMenuProps {\n items: MenuItem[];\n isSelectedHandler: (path: string | undefined) => boolean;\n onClick?: (path: string | undefined) => void;\n preMenuItemsComponent?: React.ReactNode;\n /**\n * The app that owns this menu has not reported in yet. Draws the menu's own\n * geometry in placeholder form rather than nothing: an empty column during\n * startup reads as \"this app has no menu\", and the items then appear and shove\n * the first click target somewhere else.\n */\n loading?: boolean;\n}\n\n/**\n * Placeholder in the shape of the menu: a caption, then rows at item height.\n * The geometry lives in `ContentLoading`'s `menu` shape so there is one menu\n * placeholder in the product rather than a copy per column that renders one.\n */\nconst SidebarMenuSkeleton: React.FC = () => (\n <ContentLoading variant=\"inline\" shape=\"menu\" />\n);\n\ntype SelectedHandler = (path: string | undefined) => boolean;\ntype ClickHandler = (path: string | undefined) => void;\n\nconst SidebarMenuItem: React.FC<{\n item: MenuItem;\n isSelectedHandler: SelectedHandler;\n onClick?: ClickHandler;\n depth?: number;\n}> = ({ item, isSelectedHandler, onClick, depth = 0 }) => {\n const hasChildren = Boolean(item.children && item.children.length > 0);\n const isSelected = isSelectedHandler ? isSelectedHandler(item.path) : false;\n\n // Een item met children is een sectie, geen bestemming: geen hover, geen\n // cursor, geen selectie — alleen een kop boven zijn items.\n if (hasChildren) {\n return (\n <li>\n <div\n className={cn(\n \"flex items-center gap-2 px-2.5 pt-5 pb-2 text-2xs font-semibold uppercase tracking-label text-text-disabled\",\n )}\n >\n <span className=\"min-w-0 flex-1 truncate\">{item.label}</span>\n {item.count !== undefined && item.count > 0 && (\n <span className=\"font-normal tabular-nums\">{item.count}</span>\n )}\n </div>\n <ul className=\"flex flex-col gap-px\">\n {item.children?.map((child, index) => (\n <SidebarMenuItem\n key={index}\n item={child}\n isSelectedHandler={isSelectedHandler}\n onClick={onClick}\n depth={depth + 1}\n />\n ))}\n </ul>\n </li>\n );\n }\n\n // Een hover-actie wisselt de count af in plaats van ernaast te schuiven,\n // anders verspringt de rij zodra de muis erop komt.\n const action = item.action;\n const swapsWithCount = action?.visibility !== \"always\";\n\n return (\n <li>\n <div\n role=\"button\"\n tabIndex={0}\n onClick={() => item.path && onClick?.(item.path)}\n onKeyDown={(e) => {\n if (e.key === \"Enter\" || e.key === \" \") {\n e.preventDefault();\n item.path && onClick?.(item.path);\n }\n }}\n className={cn(\n // De kolom ligt op de backdrop, niet op een paneel: het actieve item\n // is daarom een opliggende witte plaat, en de hover is de backdrop-\n // hover (donkerder) in plaats van de surface-hover (lichter).\n \"group/item flex h-row-md cursor-pointer items-center gap-2.5 rounded-md px-2.5 text-base no-underline\",\n \"transition-colors duration-fast ease-out\",\n \"focus-visible:outline-none focus-visible:focus-ring\",\n isSelected\n // `surface-hover`, not pure white: on the 0.93 backdrop a #fff plate\n // is a 7% jump and the current item shouts. Still a raised plate —\n // same language as the rail and the segmented toggle — just quieter.\n ? \"bg-surface-hover font-medium text-text shadow-sm\"\n : \"text-text-muted hover:bg-page-hover hover:text-text\",\n )}\n >\n {item.icon && (\n <span\n className={cn(\n \"flex w-5 shrink-0 items-center justify-center\",\n isSelected ? \"text-text-muted\" : \"text-text-subtle\",\n )}\n >\n {item.icon}\n </span>\n )}\n <span className=\"min-w-0 flex-1 truncate\">{item.label}</span>\n {item.count !== undefined && item.count > 0 && (\n <span\n className={cn(\n \"shrink-0 text-xs tabular-nums\",\n isSelected\n ? \"rounded-full bg-accent px-1.5 font-semibold text-accent-fg\"\n : \"text-text-subtle\",\n action && swapsWithCount && \"group-hover/item:hidden group-focus-within/item:hidden\",\n )}\n >\n {item.count}\n </span>\n )}\n {action && (\n <button\n type=\"button\"\n aria-label={action.label}\n title={action.label}\n onClick={(e) => {\n e.stopPropagation();\n action.onClick();\n }}\n // Enter/Space bubbelt anders door naar de rij en navigeert alsnog.\n onKeyDown={(e) => e.stopPropagation()}\n className={cn(\n \"flex size-5 shrink-0 items-center justify-center rounded-sm\",\n \"text-text-subtle transition-colors duration-fast ease-out\",\n \"hover:bg-page-hover hover:text-text\",\n \"focus-visible:outline-none focus-visible:focus-ring\",\n swapsWithCount &&\n \"opacity-0 group-hover/item:opacity-100 focus-visible:opacity-100\",\n )}\n >\n {action.icon}\n </button>\n )}\n </div>\n </li>\n );\n};\n\n/**\n * Sidebar — een vrij slot (zoek) en daaronder de nav-items. Secties met\n * children zijn koppen, geen knoppen.\n *\n * Géén titel en géén actie-iconen meer: de app-switcher (titel + `+`) en de\n * gebruikersvoet zijn shell-chrome en staan in `NavigationPanel`. Dit component\n * vult alleen het middenstuk van die kolom.\n */\nexport const SidebarMenu: React.FC<SidebarMenuProps> = ({\n items,\n isSelectedHandler,\n onClick,\n preMenuItemsComponent,\n loading = false,\n}) => {\n if (loading) {\n return (\n <nav className=\"flex h-full min-h-0 shrink-0 flex-col\">\n {preMenuItemsComponent && <div className=\"pb-4\">{preMenuItemsComponent}</div>}\n <SidebarMenuSkeleton />\n </nav>\n );\n }\n\n return (\n <nav className=\"flex h-full min-h-0 shrink-0 flex-col\">\n {preMenuItemsComponent && <div className=\"pb-4\">{preMenuItemsComponent}</div>}\n\n <ul className=\"flex min-h-0 flex-1 flex-col gap-px overflow-y-auto\">\n {items.map((item, index) =>\n !item.path && !item.label && !item.children ? (\n <li key={index} aria-hidden className=\"h-4\" />\n ) : (\n <SidebarMenuItem\n key={index}\n item={item}\n isSelectedHandler={isSelectedHandler}\n onClick={onClick}\n />\n )\n )}\n </ul>\n </nav>\n );\n};\n\nexport default SidebarMenu;\n","import React from 'react';\nimport { cn } from '../utils/cn';\n\nexport interface HeadingProps {\n /** Heading level */\n level?: 1 | 2 | 3 | 4 | 5 | 6;\n /** Visual size (can be different from semantic level) */\n size?: 'xs' | 'sm' | 'md' | 'lg' | 'xl' | '2xl' | '3xl' | '4xl';\n /** Font weight */\n weight?: 'light' | 'normal' | 'medium' | 'semibold' | 'bold';\n /** Text color */\n color?: 'primary' | 'secondary' | 'accent' | 'success' | 'warning' | 'error' | 'info' | 'neutral' | 'current';\n /** Text alignment */\n align?: 'left' | 'center' | 'right';\n /** Whether to truncate text with ellipsis */\n truncate?: boolean;\n /** Additional CSS classes */\n className?: string;\n /** Child content */\n children: React.ReactNode;\n}\n\n/**\n * Heading — semantic level, visual size from the token scale.\n *\n * md 13 · lg 16 (section head) · xl 20 (detail title)\n * 2xl 24 (page title) · 3xl / 4xl 30 (display)\n *\n * Default weight is semibold: the system has no 700 headings.\n */\nconst sizeMap: Record<NonNullable<HeadingProps['size']>, string> = {\n xs: 'text-xs',\n sm: 'text-sm',\n md: 'text-base',\n lg: 'text-lg',\n xl: 'text-xl',\n '2xl': 'text-2xl',\n '3xl': 'text-3xl',\n '4xl': 'text-3xl',\n};\n\nconst weightMap: Record<NonNullable<HeadingProps['weight']>, string> = {\n light: 'font-normal',\n normal: 'font-normal',\n medium: 'font-medium',\n semibold: 'font-semibold',\n bold: 'font-bold',\n};\n\nconst colorMap: Record<NonNullable<HeadingProps['color']>, string> = {\n primary: 'text-text',\n secondary: 'text-text-muted',\n accent: 'text-accent',\n success: 'text-success-fg',\n warning: 'text-warning-fg',\n error: 'text-danger-fg',\n info: 'text-info-fg',\n neutral: 'text-text',\n current: 'text-current',\n};\n\nconst alignMap: Record<NonNullable<HeadingProps['align']>, string> = {\n left: 'text-left',\n center: 'text-center',\n right: 'text-right',\n};\n\nexport const Heading: React.FC<HeadingProps> = ({\n level = 1,\n size,\n weight = 'semibold',\n color = 'current',\n align = 'left',\n truncate = false,\n className,\n children,\n ...props\n}) => {\n const Tag = `h${level}` as keyof React.JSX.IntrinsicElements;\n\n const headingClasses = cn(\n 'font-sans text-pretty',\n sizeMap[size || getDefaultSize(level)!],\n weightMap[weight],\n colorMap[color],\n alignMap[align],\n truncate && 'truncate',\n className\n );\n\n return (\n <Tag className={headingClasses} {...props}>\n {children}\n </Tag>\n );\n};\n\nfunction getDefaultSize(level: number): HeadingProps['size'] {\n const sizeMap: Record<number, HeadingProps['size']> = {\n 1: '2xl',\n 2: 'xl',\n 3: 'lg',\n 4: 'lg',\n 5: 'md',\n 6: 'md',\n };\n\n return sizeMap[level] || 'md';\n}\n","import { ChevronRight, Search } from \"lucide-react\";\nimport React, { useEffect, useRef, useState } from \"react\";\n\n// Define the types for the command palette\nexport interface Command {\n id: string;\n label: string;\n action?: () => void;\n subCommands?: Command[];\n icon?: React.ReactNode;\n}\n\nexport interface CommandPaletteProps {\n commands: Command[];\n isOpen: boolean;\n onClose: () => void;\n labels?: {\n searchPlaceholder?: string;\n navigate?: string;\n select?: string;\n close?: string;\n noCommandsFound?: string;\n };\n initialCommandPath?: string[];\n initialActiveIndex?: number;\n}\n\nconst CommandPalette: React.FC<CommandPaletteProps> = ({\n commands,\n isOpen,\n onClose,\n labels,\n initialCommandPath,\n initialActiveIndex,\n}) => {\n const [searchTerm, setSearchTerm] = useState(\"\");\n const [activeCommandPath, setActiveCommandPath] = useState<string[]>(initialCommandPath || []);\n const [activeIndex, setActiveIndex] = useState(initialActiveIndex || 0);\n const paletteRef = useRef<HTMLDivElement>(null);\n const listRef = useRef<HTMLDivElement>(null);\n\n const currentCommands = activeCommandPath.length\n ? commands.find((c) => c.id === activeCommandPath[0])?.subCommands || []\n : commands;\n\n const filteredCommands = currentCommands.filter((command) =>\n command.label.toLowerCase().includes(searchTerm.toLowerCase())\n );\n\n // Reset state when the palette is closed\n useEffect(() => {\n if (!isOpen) {\n setSearchTerm(\"\");\n setActiveCommandPath(initialCommandPath || []);\n setActiveIndex(initialActiveIndex || 0);\n }\n }, [isOpen]);\n\n // Handle keyboard navigation\n useEffect(() => {\n const handleKeyDown = (event: KeyboardEvent) => {\n if (!isOpen) return;\n\n if (event.key === \"Escape\") {\n onClose();\n } else if (event.key === \"ArrowUp\") {\n setActiveIndex((prevIndex) =>\n prevIndex > 0 ? prevIndex - 1 : filteredCommands.length - 1\n );\n } else if (event.key === \"ArrowDown\") {\n setActiveIndex((prevIndex) =>\n prevIndex < filteredCommands.length - 1 ? prevIndex + 1 : 0\n );\n } else if (event.key === \"Enter\") {\n const command = filteredCommands[activeIndex];\n if (command) {\n if (command.subCommands) {\n setActiveCommandPath([...activeCommandPath, command.id]);\n setActiveIndex(0);\n } else if (command.action) {\n command.action();\n onClose();\n }\n }\n }\n };\n\n document.addEventListener(\"keydown\", handleKeyDown);\n return () => document.removeEventListener(\"keydown\", handleKeyDown);\n }, [isOpen, onClose, filteredCommands, activeIndex, activeCommandPath]);\n\n // Handle clicks outside the palette to close it\n useEffect(() => {\n const handleClickOutside = (event: MouseEvent) => {\n if (\n paletteRef.current &&\n !paletteRef.current.contains(event.target as Node)\n ) {\n onClose();\n }\n };\n\n if (isOpen) {\n document.addEventListener(\"mousedown\", handleClickOutside);\n }\n return () => document.removeEventListener(\"mousedown\", handleClickOutside);\n }, [isOpen, onClose]);\n\n // Keep active item visible while scrolling via keyboard\n useEffect(() => {\n if (!isOpen) return;\n const el = listRef.current?.querySelector<HTMLElement>(`[data-index=\"${activeIndex}\"]`);\n el?.scrollIntoView({ block: \"nearest\" });\n }, [activeIndex, isOpen]);\n\n if (!isOpen) {\n return null;\n }\n\n return (\n <div className=\"fixed inset-0 z-modal flex items-center justify-center bg-scrim\">\n <div\n className=\"flex flex-col w-full max-w-lg max-h-dialog p-2 mx-auto rounded-lg border border-border shadow-modal bg-surface\"\n ref={paletteRef}\n >\n <div className=\"flex items-center gap-2 px-3 flex-shrink-0\">\n <Search className=\"w-4 h-4 text-text-muted shrink-0\" />\n <input\n type=\"text\"\n autoFocus\n placeholder={labels?.searchPlaceholder || \"Search commands...\"}\n value={searchTerm}\n onChange={(e) => setSearchTerm(e.target.value)}\n className=\"w-full border-0 bg-transparent py-2 text-text focus:outline-none\"\n />\n </div>\n <div\n ref={listRef}\n className=\"mt-2 pt-2 text-sm border-t border-border max-h-dialog-list overflow-y-auto\"\n >\n {filteredCommands.length === 0 && (\n <div className=\"text-text-muted text-center text-sm\">\n {labels?.noCommandsFound || \"No commands found\"}\n </div>\n )}\n {filteredCommands.map((command, index) => (\n <div\n key={command.id}\n data-index={index}\n className={`flex items-center p-2 cursor-pointer rounded-md ${index === activeIndex ? \"bg-accent-soft text-accent\" : \"text-text\"\n }`}\n onClick={() => {\n if (command.subCommands) {\n setActiveCommandPath([...activeCommandPath, command.id]);\n setActiveIndex(0);\n } else if (command.action) {\n command.action();\n onClose();\n }\n }}\n onMouseEnter={() => setActiveIndex(index)}\n >\n {command.icon && <span className=\"mr-3\">{command.icon}</span>}\n <span className=\"flex-grow\">{command.label}</span>\n {command.subCommands && (\n <span className=\"text-text-muted\">\n <ChevronRight className=\"w-4 h-4\" />\n </span>\n )}\n </div>\n ))}\n </div>\n <div className=\"flex items-center gap-4 px-3 pt-2 mt-2 text-xs text-text-muted border-t border-border\">\n <span className=\"flex items-center gap-1.5\">\n <kbd className=\"inline-flex items-center justify-center min-w-5 px-1 py-0.5 rounded border border-border bg-surface-sunk text-xs font-medium not-italic\">↑↓</kbd>\n {labels?.navigate || \"to navigate\"}\n </span>\n <span className=\"flex items-center gap-1.5\">\n <kbd className=\"inline-flex items-center justify-center min-w-5 px-1 py-0.5 rounded border border-border bg-surface-sunk text-xs font-medium not-italic\">↵</kbd>\n {labels?.select || \"to select\"}\n </span>\n <span className=\"flex items-center gap-1.5\">\n <kbd className=\"inline-flex items-center justify-center min-w-5 px-1 py-0.5 rounded border border-border bg-surface-sunk text-xs font-medium not-italic\">Esc</kbd>\n {labels?.close || \"to close\"}\n </span>\n </div>\n </div>\n </div>\n );\n};\n\nexport default CommandPalette;\n","import React, { forwardRef } from 'react';\nimport { cn } from '../utils/cn';\n\nexport interface BoxProps extends React.HTMLAttributes<HTMLDivElement> {\n /**\n * Padding size\n */\n padding?: 'none' | 'xs' | 'sm' | 'md' | 'lg' | 'xl' | '2xl';\n\n /**\n * Margin size\n */\n margin?: 'none' | 'xs' | 'sm' | 'md' | 'lg' | 'xl' | '2xl';\n\n /**\n * Background color\n */\n background?: 'none' | 'primary' | 'secondary' | 'accent' | 'success' | 'warning' | 'error' | 'info' | 'neutral' | 'white' | 'module' | 'module-subtle' | 'backdrop' | 'editor' | 'input';\n\n /**\n * Border radius\n */\n radius?: 'none' | 'sm' | 'md' | 'lg' | 'xl' | 'full';\n\n /**\n * Shadow size\n */\n shadow?: 'none' | 'sm' | 'md' | 'lg' | 'xl' | '2xl';\n\n /**\n * Border width\n */\n border?: 'none' | 'sm' | 'md' | 'lg';\n\n /**\n * Border color\n */\n borderColor?: 'primary' | 'secondary' | 'accent' | 'success' | 'warning' | 'error' | 'info' | 'neutral' | 'white';\n}\n\n/** 4px spacing scale only. */\nconst paddingMap = {\n none: 'p-0',\n xs: 'p-1',\n sm: 'p-2',\n md: 'p-4',\n lg: 'p-6',\n xl: 'p-8',\n '2xl': 'p-12',\n};\n\nconst marginMap = {\n none: 'm-0',\n xs: 'm-1',\n sm: 'm-2',\n md: 'm-4',\n lg: 'm-6',\n xl: 'm-8',\n '2xl': 'm-12',\n};\n\n/** Semantic surfaces — the legacy `module` names stay as aliases. */\nconst backgroundMap = {\n none: '',\n primary: 'bg-accent text-accent-fg',\n secondary: 'bg-surface-hover',\n accent: 'bg-accent-soft',\n success: 'bg-success-soft',\n warning: 'bg-warning-soft',\n error: 'bg-danger-soft',\n info: 'bg-info-soft',\n neutral: 'bg-surface-hover',\n white: 'bg-surface',\n module: 'bg-surface',\n 'module-subtle': 'bg-surface-sunk',\n backdrop: 'bg-page',\n editor: 'bg-surface',\n input: 'bg-surface-input',\n};\n\nconst radiusMap = {\n none: 'rounded-none',\n sm: 'rounded-sm',\n md: 'rounded-md',\n lg: 'rounded-lg',\n xl: 'rounded-xl',\n full: 'rounded-full',\n};\n\n/**\n * Elevation: cards are defined by their border, not a shadow — `sm` is\n * intentionally flat. Shadows only mean \"this floats above the page\".\n */\nconst shadowMap = {\n none: 'shadow-none',\n sm: 'shadow-none',\n md: 'shadow-overlay',\n lg: 'shadow-overlay',\n xl: 'shadow-modal',\n '2xl': 'shadow-modal',\n};\n\nconst borderMap = {\n none: 'border-0',\n sm: 'border',\n md: 'border-2',\n lg: 'border-4',\n};\n\nconst borderColorMap = {\n primary: 'border-accent-border',\n secondary: 'border-border',\n accent: 'border-accent-border',\n success: 'border-success-border',\n warning: 'border-warning-border',\n error: 'border-danger-border',\n info: 'border-info-border',\n neutral: 'border-border-subtle',\n white: 'border-border-subtle',\n};\n\n/**\n * Box primitive component for layout and styling\n *\n * @example\n * ```tsx\n * <Box padding=\"md\" background=\"module\" radius=\"lg\" border=\"sm\" borderColor=\"neutral\">\n * Content\n * </Box>\n * ```\n */\nexport const Box = forwardRef<HTMLDivElement, BoxProps>(\n (\n {\n padding,\n margin,\n background,\n radius,\n shadow,\n border,\n borderColor,\n className,\n children,\n ...props\n },\n ref\n ) => {\n return (\n <div\n ref={ref}\n className={cn(\n padding && paddingMap[padding],\n margin && marginMap[margin],\n background && backgroundMap[background],\n radius && radiusMap[radius],\n shadow && shadowMap[shadow],\n border && borderMap[border],\n borderColor && borderColorMap[borderColor],\n className\n )}\n {...props}\n >\n {children}\n </div>\n );\n }\n);\n\nBox.displayName = 'Box';\n","import { Box, BoxProps } from \"./Box\";\n\nexport interface CardProps extends BoxProps {\n children: React.ReactNode;\n title?: string;\n}\n\n/**\n * Card — panel on a page background. Border, never a shadow (radius-lg = 12px).\n */\nexport const Card = ({ children, title, ...props }: CardProps) => {\n return (\n <Box\n background=\"module\"\n radius=\"lg\"\n shadow=\"none\"\n border=\"sm\"\n borderColor=\"neutral\"\n {...props}\n >\n {title && (\n <span className=\"mb-2 block text-sm font-semibold text-text\">{title}</span>\n )}\n {children}\n </Box>\n );\n};\n","import React, { useEffect, useRef, useState } from \"react\";\n\ninterface FederatedResourceProps {\n identifier: string;\n resourceLoader: () => Promise<any>;\n framework?: 'react' | 'svelte' | 'vanilla';\n /** Getoond zolang de remote laadt. */\n fallback?: React.ReactNode;\n /**\n * Getoond wanneer de remote niet te laden is — app uitgezet, bundel stuk, sleutel fout.\n *\n * Zonder dit rendert dit component bij een fout niets, en dan verdwijnt de plek waar\n * iets had moeten staan zonder spoor in de UI. Dat is precies het verschil tussen \"de\n * app is er niet\" en \"er is niks aan de hand\".\n */\n errorFallback?: React.ReactNode;\n componentProps?: Record<string, any>;\n className?: string;\n}\n\n/**\n * Remotes die al een keer opgehaald zijn, op identifier.\n *\n * Zonder dit gaf élke identifier-wissel een leeg scherm: het component liet de huidige\n * remote los, toonde de `fallback` en ging op een promise wachten — óók als de bundel al\n * in het geheugen zat en die promise op de volgende tick zou resolven. Op een pagina die\n * bij het navigeren van resource wisselt (een publiek helpcentrum, een app die van lijst\n * naar editor gaat) is dat een schermvullende flits per klik.\n *\n * Module Federation cachet de onderliggende import zelf al; dit haalt dus de render-ronde\n * weg, niet een netwerkronde. Een app die tijdens de sessie vervangen wordt houdt daarmee\n * zijn oude module — net als vandaag, want die MF-cache zit er toch al tussen.\n */\nconst loadedRemotes = new Map<string, any>();\n\nexport function FederatedResource({\n identifier,\n resourceLoader,\n framework = 'react',\n fallback,\n errorFallback,\n componentProps,\n className,\n}: FederatedResourceProps) {\n const containerRef = useRef<HTMLDivElement>(null);\n const [failedId, setFailedId] = useState<string | null>(null);\n const [, bump] = useState(0);\n\n const svelteInstanceRef = useRef<any>(null);\n\n /**\n * De loader in een ref, en het effect alleen op `identifier`.\n *\n * Vrijwel elke aanroeper geeft een inline arrow mee (`() => sdk.resources.get(...)`).\n * Die heeft elke render een nieuwe identiteit, dus met de loader in de deps-array laadde\n * dit component bij élke render opnieuw. Onopvallend bij één paneel; niet bij een\n * feedrij per gesprek. `identifier` is de echte identiteit van de resource.\n *\n * Dit raakt `componentProps` niet: die worden in de render gespreid\n * (`<ExternalComponent {...componentProps} />`), niet in dit effect. Wijzigen ze, dan\n * hertekent dit component en krijgt de remote ze meteen — het is juist de bedoeling dat\n * de *bundel* niet opnieuw wordt gehaald omdat er een prop veranderde.\n *\n * Voor svelte lopen prop-updates via `$set` in het effect onderaan. Een `vanilla`-remote\n * krijgt zijn props alleen bij mount; er is vandaag geen enkele app die iets anders dan\n * `react` declareert, dus dat blijft een open eind in plaats van een geraden API.\n */\n const loaderRef = useRef(resourceLoader);\n loaderRef.current = resourceLoader;\n\n useEffect(() => {\n if (loadedRemotes.has(identifier)) return;\n\n let isMounted = true;\n\n const load = async () => {\n try {\n const module = await loaderRef.current();\n if (!isMounted) return;\n loadedRemotes.set(identifier, module);\n bump((n) => n + 1);\n } catch (err) {\n console.error(`[FederatedResource] Load failed: ${identifier}`, err);\n if (isMounted) setFailedId(identifier);\n }\n };\n\n void load();\n return () => { isMounted = false; };\n }, [identifier]);\n\n /*\n * Alles wordt in de render afgeleid uit `identifier`, niet uit state.\n *\n * State die bij de vórige identifier hoort is hier gevaarlijk: een effect draait ná de\n * paint, dus bij een wissel is er één frame waarin de oude remote de props van de\n * nieuwe krijgt. Dat is precies het moment waarop een pagina op een prop crasht die er\n * voor haar niet hoort te zijn.\n */\n const module = loadedRemotes.get(identifier) ?? null;\n // `!module` eerst: wisselt de identifier weg van een mislukte remote en weer terug, dan\n // probeert het effect het opnieuw. Slaagt die poging, dan mag de oude foutmelding niet\n // naast het geladen component blijven staan.\n const failed = !module && failedId === identifier;\n const isLoading = !module && !failed;\n\n const ExternalComponent = module\n ? framework === 'react'\n ? (module.component || module.default || module)\n : module\n : null;\n\n useEffect(() => {\n if (!ExternalComponent || framework === 'react') return;\n\n const target = containerRef.current;\n if (!target) return;\n\n if (framework === 'svelte') {\n const Component = ExternalComponent.default || ExternalComponent;\n const instance = new Component({ target, props: componentProps || {} });\n svelteInstanceRef.current = instance;\n return () => instance.$destroy();\n }\n\n if (ExternalComponent.mount) {\n const cleanup = ExternalComponent.mount({ container: target, props: componentProps || {} });\n return () => {\n if (typeof cleanup === 'function') cleanup();\n else ExternalComponent.unmount?.(target);\n };\n }\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [ExternalComponent, framework]);\n\n useEffect(() => {\n if (framework === 'svelte' && svelteInstanceRef.current) {\n svelteInstanceRef.current.$set?.(componentProps);\n }\n }, [componentProps, framework]);\n\n return (\n <div ref={containerRef} className={className} style={{ display: 'contents' }}>\n {isLoading && fallback}\n {failed && errorFallback}\n\n {framework === 'react' && ExternalComponent && (\n <ExternalComponent {...componentProps} />\n )}\n </div>\n );\n}\n","import type { ErrorInfo, ReactNode } from \"react\";\nimport { Component } from \"react\";\n\ninterface Props {\n children: ReactNode;\n fallback?: ReactNode;\n name?: string;\n}\n\ninterface State {\n hasError: boolean;\n error: Error | null;\n}\n\nexport class ErrorBoundary extends Component<Props, State> {\n public state: State = {\n hasError: false,\n error: null,\n };\n\n public static getDerivedStateFromError(error: Error): State {\n return { hasError: true, error };\n }\n\n public componentDidCatch(error: Error, errorInfo: ErrorInfo) {\n console.error(`[ErrorBoundary] Error in ${this.props.name || 'Component'}:`, error, errorInfo);\n }\n\n public render() {\n if (this.state.hasError) {\n if (this.props.fallback) {\n return this.props.fallback;\n }\n\n return (\n <div className=\"p-4 m-4 border border-danger-border bg-danger-soft rounded-lg\">\n <h2 className=\"text-lg font-semibold text-danger-fg\">Something went wrong</h2>\n <p className=\"text-sm text-danger-fg mt-1\">\n {this.props.name ? `Error in ${this.props.name}` : 'The component failed to render.'}\n </p>\n <button\n className=\"mt-4 px-4 py-2 bg-danger text-danger-fg rounded hover:opacity-90 transition-opacity text-sm\"\n onClick={() => this.setState({ hasError: false, error: null })}\n >\n Try again\n </button>\n </div>\n );\n }\n\n return this.props.children;\n }\n}\n"],"names":["cn","inputs","clsx","createVariants","variants","variant","value","createSizes","sizes","size","useAnchoredPosition","open","anchorRef","gap","matchWidth","placement","style","setStyle","useState","useLayoutEffect","place","anchor","rect","spaceBelow","spaceAbove","wantsTop","flip","onTop","next","IDENTITY_TONE_COUNT","hash","seed","h","i","identityTone","key","PLATE","SOLID","identityPlateClass","identityDotClass","TONES","catTone","id","text","normalizeText","MeetingGrid","tiles","pinned","className","jsx","t","cols","ParticipantTile","name","avatarUrl","muted","speaking","hasVideo","videoSlot","fill","jsxs","VideoOff","User","MicOff","Mic","VideoSurface","attach","active","mirrored","ref","useRef","useEffect","cleanup","buttonVariants","buttonSizes","iconOnlySizes","Button","forwardRef","fullWidth","loading","leftIcon","rightIcon","iconOnly","shape","children","disabled","props","isDisabled","ButtonGroup","orientation","attached","baseClasses","resolveLucideIcon","pascal","part","found","LucideIcons","colorMap","Icon","IconComponent","color","clickable","onClick","ariaLabel","sizeValue","getSizeValue","iconClasses","iconProps","e","Popover","trigger","rootClassName","triggerClassName","triggerLabel","isOpen","setIsOpen","rootRef","triggerRef","panelStyle","onDown","event","onEsc","handleToggle","close","tones","chipShell","opts","chipBody","FilterChip","label","icon","tone","caret","menu","menuClassName","onClear","clearLabel","title","showClear","radius","shell","body","Fragment","ChevronDown","bodyClasses","clearButton","X","sizeMap","buttonBackgroundMap","Link","external","href","target","rel","isExternal","linkProps","ExternalLink","SegmentedToggle","options","onChange","opt","variantStyles","chevronSizes","SplitButton","menuPlacement","menuLabel","hasMenu","option","checkboxSizes","rowSizes","labelSizes","Checkbox","helperText","error","indeterminate","containerClassName","labelClassName","reactId","React","checkboxId","hasError","innerRef","setRefs","node","weightMap","alignMap","lineHeightMap","Text","weight","align","truncate","italic","underline","lineHeight","as","Tag","getDefaultElement","isCaption","isLabel","isCode","textClasses","ImageField","maxDimension","maxBytes","aspect","chooseLabel","removeLabel","tooLargeLabel","inputRef","setError","handleSelect","file","encoded","downscaleToDataUri","approximateBytes","dataUri","base64","padding","resolve","reject","reader","img","scale","width","height","canvas","ctx","CalendarIcon","Calendar","ChevronLeftIcon","ChevronLeft","ChevronRightIcon","ChevronRight","DatePicker","placeholder","required","minDate","maxDate","format","withTime","currentMonth","setCurrentMonth","containerRef","fieldRef","handleClickOutside","formatDate","date","day","month","year","datePart","formatTime","handleTimeChange","hours","minutes","base","getCalendarDays","firstDay","startDate","days","current","handleDateSelect","picked","handlePrevMonth","handleNextMonth","handleClear","inputClasses","calendarDays","monthNames","index","isCurrentMonth","isSelected","isToday","selectSizes","norm","Select","searchable","multiple","allowCreate","onCreateOption","selectId","searchTerm","setSearchTerm","localOptions","setLocalOptions","includesOption","needle","o","ensureValuesInOptions","baseOptions","currentValue","out","addIfMissing","v","val","prev","selected","optionValue","currentValues","newValues","selectedOption","selectedOptions","filteredOptions","canCreate","createOption","labelToCreate","clean","newOption","getDisplayValue","ChevronDownIcon","inputSizes","fieldLabelClasses","fieldFrameClasses","fieldEdgeClasses","TextField","startIcon","endIcon","inputId","describedBy","FolderSelect","onListFolders","templatePlaceholder","showTemplate","folders","setFolders","res","f","classes","SearchIcon","Search","iconSizes","SearchableTextField","externalLoading","onRemoteSearch","onSelect","debounceTime","showAllOnOpen","propValue","inputValue","setInputValue","isSearchingRemote","setIsSearchingRemote","typedSinceOpen","setTypedSinceOpen","useMemo","lowerCaseInput","handler","handleChange","newValue","handleFocus","showDropdown","resolvedRef","Loader2","SearchField","onValueChange","hint","Switch","checked","track","Dropdown","showCheck","header","hoveredOption","setHoveredOption","submenuPosition","setSubmenuPosition","dropdownRef","submenuRef","menuRef","menuPos","hideTimeoutRef","menuItems","handleMenuKeyDown","items","handleEscape","hoveredElement","handleTriggerClick","handleOptionClick","parentValue","handleOptionHover","handleOptionLeave","handleSubmenuOptionClick","dropdownClasses","submenuClasses","hasChildren","isHovered","Check","childOption","childIndex","totalOptions","count","childCount","child","PageToolbarActions","actions","defaultVariant","action","paddingClasses","PageToolbar","onBack","backLabel","dateFilterHandler","fn","selectFilterHandler","cellPadding","rowHeights","SKELETON_ROWS","SKELETON_WIDTHS","pageWindow","total","_","sorted","p","a","b","page","FilterMenu","values","labelOf","pick","Table","data","columns","searchPlaceholder","searchValue","onSearchChange","filters","toolbarActions","paginated","defaultPageSize","onRowClick","selectable","selectedRows","onSelectionChange","getRowKey","row","emptyContent","footerSummary","hoverable","rowClassName","headerBackground","internalSearch","setInternalSearch","controlledSearch","sortState","setSortState","pagination","setPagination","tableRef","filteredData","result","searchableColumns","col","lowerSearchTerm","column","filter","sortedData","aValue","bValue","comparison","paginatedData","startIndex","endIndex","handleSort","useCallback","columnId","handlePageChange","newPage","handleRowSelection","rowKey","handleSelectAll","totalItems","totalPages","startItem","endItem","allVisibleSelected","selectedRow","someVisibleSelected","pad","headerFill","cellClasses","showToolbar","showPaginator","showFooter","ChevronUp","rowIndex","columnIndex","Ellipsis","actionId","entry","TabsContext","createContext","TabBar","activeTab","onTabChange","internalActiveTab","setInternalActiveTab","currentActiveTab","handleTabClick","tabId","item","Tabs","defaultTab","handleTabChange","contextValue","activeTabItem","tabListClasses","tabClasses","isActive","sizeClasses","variantClasses","stateClasses","activeClasses","inactiveClasses","modalSizes","Modal","onClose","closeOnBackdropClick","closeOnEscape","backdropClassName","footer","showCloseButton","modalRef","previousActiveElement","handleBackdropClick","StorageInput","accept","onListFiles","onListMounts","onUploadFile","onDownloadFile","onRegisterFile","isModalOpen","setIsModalOpen","mounts","setMounts","selectedMount","setSelectedMount","currentPath","setCurrentPath","remoteFiles","setRemoteFiles","setLoading","selectedPointer","setSelectedPointer","isCreatingFolder","setIsCreatingFolder","newFolderName","setNewFolderName","fileInputRef","loadMounts","loadFiles","resp","err","handleLocalOnlySelection","buffer","content","virtualPointer","handleUploadToStorage","pointer","handleCreateFolder","fullPath","handleSelectRemote","explorerItems","files","path","parts","handleFolderClick","folderName","handleGoBack","tableData","explorerColumns","Folder","FileText","mountColumns","HardDrive","ArrowLeft","FolderPlus","Upload","textareaSizes","TextArea","rows","textareaId","REAL_TOKENS","autofillProps","token","getValueByPath","obj","acc","setValueByPath","keys","clone","cur","k","unsetByPath","FormSection","description","Form","groups","externalData","onSubmit","onCancel","transform","validate","submitButton","cancelButton","showButtons","layout","sdk","formData","setFormData","errors","setErrors","touched","setTouched","validateField","currentData","field","group","arrayErrors","hasErrors","rowErrors","subField","subFieldValue","handleFieldChange","newData","g","handleSubmit","newErrors","allFields","formErrors","finalData","renderField","commonProps","payload","fileId","arrayValue","handleAddItem","handleRemoveItem","handleSubFieldChange","fieldName","fieldValue","newArray","subFieldError","commonSubFieldProps","dateValue","Trash2","Plus","renderGroup","visibleItems","groupClasses","fieldError","formClasses","buttonSize","ConfirmDialog","confirmLabel","cancelLabel","onConfirm","badgeVariants","badgeSizes","dotColors","Badge","dot","dismissible","onDismiss","Bar","Shape","r","c","DEFAULT_ROWS","ContentLoading","showTableSkeleton","tableColumns","tableRows","resolvedShape","resolvedRows","resolvedColumns","inner","toneDisc","EmptyState","card","Kbd","trackSizes","fillVariants","ProgressBar","pct","spinnerSizes","spinnerColors","Spinner","showLabel","StatusDot","pulse","StepIndicator","steps","activeIndex","shared","step","HTML_TAG","HTML_PROSE","components","RichText","src","DOMPurify","Markdown","remarkGfm","KPI_TONE","CALLOUT_TONE","KPI_COLUMNS","Block","block","List","cellIndex","ArtifactView","blocks","runtime","AssistantCard","Sparkles","toneClasses","initials","Avatar","errored","setErrored","RING","OWNER_RING","AvatarStack","people","max","shown","overflow","CH","ChannelBadge","channel","known","Image","alt","aspectRatio","showLoading","showError","fallback","loadingContent","errorContent","onLoad","onError","isLoading","setIsLoading","setHasError","currentSrc","setCurrentSrc","handleLoad","handleError","containerClasses","imageClasses","placeholderClasses","defaultLoadingContent","defaultErrorContent","ImageOff","ListBulkAction","leading","renderItem","trailing","onActiveIndexChange","unread","dimmed","groupBy","renderGroupHeader","stickyGroupHeaders","collapsibleGroups","hideGroupCount","selectedItems","bulkActions","stickyHeader","bordered","loadingRows","collapsed","setCollapsed","handleKeyDown","keyOf","toggle","toggleAll","container","allSelected","someSelected","renderRow","firstInBlock","isUnread","isDimmed","buckets","declared","groupIndex","isCollapsed","MessageBubble","side","continued","valueTone","KpiCard","PageHeader","surface","subtitle","meta","backClassName","editable","onTitleChange","isEditing","setIsEditing","editValue","setEditValue","handleTitleClick","handleBlur","Pencil","Page","headerContent","loadingShape","empty","scroll","contentClassName","SectionCaption","SectionDivider","rule","SettingsFrameContext","SettingsFrameProvider","useSettingsFrame","useContext","useSettingsFrameHost","state","setState","api","ownerId","SettingsPage","secondaryActions","frame","useId","backRef","hasBack","SettingsRow","control","SettingsSection","SourceChip","dotColor","ArrowUpRight","badgeColumn","config","accessor","visible","sortable","_value","raw","booleanBadgeColumn","onLabel","offLabel","onTone","offTone","on","labelsColumn","separator","labelled","code","View","formatCheckbox","getOptionLabel","subValue","displayValue","formatted","viewClasses","SidebarMenuSkeleton","SidebarMenuItem","isSelectedHandler","depth","swapsWithCount","SidebarMenu","preMenuItemsComponent","Heading","level","headingClasses","getDefaultSize","CommandPalette","commands","labels","initialCommandPath","initialActiveIndex","activeCommandPath","setActiveCommandPath","setActiveIndex","paletteRef","listRef","filteredCommands","command","prevIndex","paddingMap","marginMap","backgroundMap","radiusMap","shadowMap","borderMap","borderColorMap","Box","margin","background","shadow","border","borderColor","Card","loadedRemotes","FederatedResource","identifier","resourceLoader","framework","errorFallback","componentProps","failedId","setFailedId","bump","svelteInstanceRef","loaderRef","isMounted","module","n","failed","ExternalComponent","Component","instance","ErrorBoundary","errorInfo"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.cjs","sources":["../src/utils/cn.ts","../src/utils/useAnchoredPosition.ts","../src/utils/identity.ts","../src/utils/catTone.ts","../src/utils/text.ts","../src/meeting/MeetingGrid.tsx","../src/meeting/ParticipantTile.tsx","../src/meeting/VideoSurface.tsx","../src/action/Button.tsx","../src/action/ButtonGroup.tsx","../src/content/Icon.tsx","../src/overlays/Popover.tsx","../src/action/FilterChip.tsx","../src/action/Link.tsx","../src/action/SegmentedToggle.tsx","../src/action/SplitButton.tsx","../src/input/Checkbox.tsx","../src/typography/Text.tsx","../src/input/ImageField.tsx","../src/input/DatePicker.tsx","../src/input/Select.tsx","../src/input/TextField.tsx","../src/input/FolderSelect.tsx","../src/input/SearchableTextField.tsx","../src/input/SearchField.tsx","../src/input/Switch.tsx","../src/overlays/Dropdown.tsx","../src/content/PageToolbar.tsx","../src/content/Table.tsx","../src/navigation/Tabs.tsx","../src/overlays/Modal.tsx","../src/input/StorageInput.tsx","../src/input/TextArea.tsx","../src/forms/autofill.ts","../src/forms/Form.tsx","../src/overlays/ConfirmDialog.tsx","../src/feedback/Badge.tsx","../src/feedback/ContentLoading.tsx","../src/feedback/EmptyState.tsx","../src/feedback/Kbd.tsx","../src/feedback/ProgressBar.tsx","../src/feedback/Spinner.tsx","../src/feedback/StatusDot.tsx","../src/feedback/StepIndicator.tsx","../src/content/RichText.tsx","../src/content/ArtifactView.tsx","../src/content/AssistantCard.tsx","../src/content/Avatar.tsx","../src/content/AvatarStack.tsx","../src/content/ChannelBadge.tsx","../src/content/Image.tsx","../src/content/List.tsx","../src/content/MessageBubble.tsx","../src/content/KpiCard.tsx","../src/content/PageHeader.tsx","../src/content/Page.tsx","../src/content/SectionCaption.tsx","../src/content/SectionDivider.tsx","../src/content/SettingsPage.tsx","../src/content/SettingsRow.tsx","../src/content/SourceChip.tsx","../src/content/tableColumns.tsx","../src/content/View.tsx","../src/navigation/Sidebar.tsx","../src/typography/Heading.tsx","../src/command-palette/CommandPalette.tsx","../src/primitives/Box.tsx","../src/primitives/Card.tsx","../src/federated-resource/index.tsx","../src/error-boundary/index.tsx"],"sourcesContent":["import { clsx, type ClassValue } from 'clsx';\n\n/**\n * Utility function for combining class names\n * Combines clsx for conditional classes with Tailwind merge for deduplication\n */\nexport function cn(...inputs: ClassValue[]) {\n return clsx(inputs);\n}\n\n/**\n * Utility for creating variant-based class combinations\n */\nexport function createVariants<T extends Record<string, Record<string, string>>>(\n variants: T\n) {\n return (variant: keyof T, value: keyof T[keyof T]) => {\n return variants[variant]?.[value] || '';\n };\n}\n\n/**\n * Utility for creating size-based class combinations\n */\nexport function createSizes<T extends Record<string, string>>(sizes: T) {\n return (size: keyof T) => sizes[size] || '';\n} ","import { useLayoutEffect, useState, type CSSProperties, type RefObject } from \"react\";\n\nexport interface AnchoredPositionOptions {\n /** Gap between the anchor and the panel, in px. */\n gap?: number;\n /** Match the panel's width to the anchor — what a select wants, a menu does not. */\n matchWidth?: boolean;\n /** Preferred side. Flips automatically when there is no room. */\n placement?: \"bottom-start\" | \"bottom-end\" | \"top-start\" | \"top-end\";\n}\n\n/**\n * Position a floating panel against its trigger, in viewport coordinates.\n *\n * Two problems this solves, both of which a plain `absolute` panel has:\n * an ancestor with `overflow-hidden` (a bordered form panel, a scroll area)\n * clips the panel, and a trigger near the bottom of the window opens a panel\n * that runs off-screen. Fixed coordinates escape every ancestor, and the\n * placement flips upward when the space below is too small.\n *\n * Recomputes on scroll and resize while open, so the panel tracks its trigger\n * instead of detaching when the page moves under it.\n */\nexport function useAnchoredPosition(\n open: boolean,\n anchorRef: RefObject<HTMLElement | null>,\n { gap = 6, matchWidth = false, placement = \"bottom-start\" }: AnchoredPositionOptions = {}\n): CSSProperties {\n const [style, setStyle] = useState<CSSProperties>({});\n\n // Layout effect, not effect: measure and place before the browser paints,\n // otherwise the panel is visible at the wrong spot for a frame.\n useLayoutEffect(() => {\n if (!open) return;\n\n const place = () => {\n const anchor = anchorRef.current;\n if (!anchor) return;\n\n const rect = anchor.getBoundingClientRect();\n const spaceBelow = window.innerHeight - rect.bottom;\n const spaceAbove = rect.top;\n\n // Flip up only when below genuinely cannot hold a usable panel and above\n // has more room — flipping into an equally cramped space helps nobody.\n const wantsTop = placement.startsWith(\"top\");\n const flip = wantsTop\n ? spaceAbove < 200 && spaceBelow > spaceAbove\n : spaceBelow < 200 && spaceAbove > spaceBelow;\n const onTop = wantsTop !== flip;\n\n const next: CSSProperties = { position: \"fixed\" };\n\n if (onTop) {\n next.bottom = window.innerHeight - rect.top + gap;\n next.maxHeight = Math.max(120, spaceAbove - gap * 2);\n } else {\n next.top = rect.bottom + gap;\n next.maxHeight = Math.max(120, spaceBelow - gap * 2);\n }\n\n if (placement.endsWith(\"end\")) next.right = window.innerWidth - rect.right;\n else next.left = rect.left;\n\n if (matchWidth) next.width = rect.width;\n\n setStyle(next);\n };\n\n place();\n // `true` captures scrolls on any ancestor, not just the window.\n window.addEventListener(\"scroll\", place, true);\n window.addEventListener(\"resize\", place);\n return () => {\n window.removeEventListener(\"scroll\", place, true);\n window.removeEventListener(\"resize\", place);\n };\n }, [open, anchorRef, gap, matchWidth, placement]);\n\n return style;\n}\n","/**\n * Deterministic colour for a thing that has a name but no status.\n *\n * The rule this exists to enforce: the same name gets the same colour\n * everywhere in the product. Every surface that used to pick a plate colour did\n * it locally — an index in a list, a hash of its own, or a fixed neutral — so\n * one person could be blue in the inbox and grey on a task, and the colour\n * carried no information at all.\n *\n * The palette is the `--color-cat-*` categorical set, which the design system\n * defines for exactly this: equal chroma and lightness, so no entry outranks\n * another, and dark mode is handled by the tokens rather than here.\n */\n\n/** How many `--color-cat-N` entries the design system defines. */\nexport const IDENTITY_TONE_COUNT = 5;\n\nexport type IdentityTone = 1 | 2 | 3 | 4 | 5;\n\n/**\n * FNV-1a. Small, stable across runs and platforms, and well spread for short\n * strings — `Math.random` would break the whole point, and summing char codes\n * collides badly on names that are anagrams (\"Bram\"/\"Marb\") or differ only in\n * order (\"Team A\"/\"A Team\").\n */\nfunction hash(seed: string): number {\n let h = 0x811c9dc5;\n for (let i = 0; i < seed.length; i++) {\n h ^= seed.charCodeAt(i);\n h = Math.imul(h, 0x01000193);\n }\n return h >>> 0;\n}\n\n/**\n * Normalised so that the same identity written differently still lands on the\n * same colour: casing and surrounding whitespace never distinguish two names.\n */\nexport function identityTone(seed: string | undefined | null): IdentityTone {\n const key = (seed ?? \"\").trim().toLowerCase();\n if (!key) return 1;\n return ((hash(key) % IDENTITY_TONE_COUNT) + 1) as IdentityTone;\n}\n\n/**\n * Whole class names, not interpolated fragments: Tailwind scans source text, so\n * `bg-cat-${n}-soft` would compile to nothing and the plate would come out\n * transparent.\n */\nconst PLATE: Record<IdentityTone, string> = {\n 1: \"bg-cat-1-soft text-cat-1-fg\",\n 2: \"bg-cat-2-soft text-cat-2-fg\",\n 3: \"bg-cat-3-soft text-cat-3-fg\",\n 4: \"bg-cat-4-soft text-cat-4-fg\",\n 5: \"bg-cat-5-soft text-cat-5-fg\",\n};\n\nconst SOLID: Record<IdentityTone, string> = {\n 1: \"bg-cat-1\",\n 2: \"bg-cat-2\",\n 3: \"bg-cat-3\",\n 4: \"bg-cat-4\",\n 5: \"bg-cat-5\",\n};\n\n/** Wash + readable mark, for a plate that holds a monogram or a glyph. */\nexport function identityPlateClass(seed: string | undefined | null): string {\n return PLATE[identityTone(seed)];\n}\n\n/** The solid colour, for a dot or a rule. */\nexport function identityDotClass(seed: string | undefined | null): string {\n return SOLID[identityTone(seed)];\n}\n","/** The categorical set — identity without status. See --color-cat-*. */\nexport type CatTone = \"cat-1\" | \"cat-2\" | \"cat-3\" | \"cat-4\" | \"cat-5\";\n\nconst TONES: CatTone[] = [\"cat-1\", \"cat-2\", \"cat-3\", \"cat-4\", \"cat-5\"];\n\n/**\n * A stable colour for a thing that has an identity but no state — a knowledge\n * base, an inbox, a team, a transcript speaker.\n *\n * Derived from the id, so the colour survives reloads and is the same for every\n * user. Storing one would mean a column per entity that wants a dot; a hash\n * gets the same result for free, and the categorical tokens are equal-weight by\n * construction so no entry can accidentally outrank another.\n */\nexport function catTone(id: string): CatTone {\n let hash = 0;\n for (let i = 0; i < id.length; i++) hash = (hash * 31 + id.charCodeAt(i)) >>> 0;\n return TONES[hash % TONES.length];\n}\n","/**\n * Coerce an unknown value to text.\n *\n * Every input component in this kit declares its `value` as `string`, and every\n * one of them is fed straight out of form data, which is `any`. A field whose\n * entity type is numeric therefore arrives as a number — `eylo-voip`'s time\n * rules do exactly that (`interval?: number`, `days?: number[]`) — and the two\n * failure modes are both silent from the type system's side:\n *\n * - a hard `TypeError: (…).trim is not a function` the moment anything calls a\n * string method on it;\n * - a comparison that simply never matches, because `1 === \"1\"` is false, so a\n * stored option renders as unselected with no error at all.\n *\n * `null` and `undefined` become `\"\"` so callers can treat \"absent\" and \"empty\"\n * alike, which is what a text input does anyway.\n */\nexport const text = (value: unknown): string => (value == null ? \"\" : String(value));\n\n/** {@link text} folded to a comparable key: trimmed and lower-cased. */\nexport const normalizeText = (value: unknown): string => text(value).trim().toLowerCase();\n","import type { ReactNode } from \"react\";\nimport { cn } from \"../utils/cn\";\n\nexport interface MeetingGridProps {\n tiles: ReactNode[];\n pinned?: ReactNode;\n className?: string;\n}\n\n/**\n * Layout primitive for meeting views. When `pinned` is provided it gets the\n * dominant area and remaining tiles render in a sidebar/strip. Otherwise tiles\n * flow in an auto-sized grid.\n */\nexport function MeetingGrid({ tiles, pinned, className }: MeetingGridProps) {\n if (pinned) {\n return (\n <div className={cn(\"flex flex-col md:flex-row gap-2 h-full min-h-0\", className)}>\n <div className=\"flex-1 min-h-0\">{pinned}</div>\n {tiles.length > 0 && (\n <div className=\"flex md:flex-col gap-2 md:w-48 overflow-auto\">\n {tiles.map((t, i) => (\n <div key={i} className=\"min-w-40 md:min-w-0\">{t}</div>\n ))}\n </div>\n )}\n </div>\n );\n }\n\n const cols = tiles.length <= 1 ? \"grid-cols-1\"\n : tiles.length <= 4 ? \"grid-cols-2\"\n : tiles.length <= 9 ? \"grid-cols-3\"\n : \"grid-cols-4\";\n\n return (\n <div className={cn(\"grid gap-2 h-full\", cols, className)}>\n {tiles.map((t, i) => (\n <div key={i}>{t}</div>\n ))}\n </div>\n );\n}\n","import { Mic, MicOff, User, VideoOff } from \"lucide-react\";\nimport type { ReactNode } from \"react\";\nimport { cn } from \"../utils/cn\";\n\nexport interface ParticipantTileProps {\n name: string;\n avatarUrl?: string;\n muted?: boolean;\n speaking?: boolean;\n hasVideo?: boolean;\n videoSlot?: ReactNode;\n className?: string;\n /**\n * Fill the parent box (height + width) instead of keeping a 16:9 aspect\n * ratio. Use for a pinned/main tile inside a bounded container so it fits the\n * available space without deriving its height from its width (which would\n * overflow a wide surface). Grid thumbnails keep the default aspect ratio.\n */\n fill?: boolean;\n}\n\n/**\n * Provider-agnostic participant tile. Shows avatar + name when no video is\n * available; otherwise renders the `videoSlot` passed by the caller (typically\n * a <VideoSurface /> wired to a provider-specific stream renderer).\n */\nexport function ParticipantTile({\n name,\n avatarUrl,\n muted,\n speaking,\n hasVideo,\n videoSlot,\n className,\n fill,\n}: ParticipantTileProps) {\n return (\n <div\n className={cn(\n \"relative rounded-lg overflow-hidden bg-video-surface flex items-center justify-center\",\n fill ? \"h-full w-full\" : \"aspect-video\",\n speaking && \"ring-2 ring-speaking\",\n className,\n )}\n >\n {hasVideo && videoSlot ? (\n <div className=\"absolute inset-0\">{videoSlot}</div>\n ) : (\n <div className=\"flex flex-col items-center gap-2 text-gray-300\">\n {avatarUrl ? (\n <img src={avatarUrl} alt={name} className=\"w-16 h-16 rounded-full object-cover\" />\n ) : (\n <div className=\"w-16 h-16 rounded-full bg-video-surface-strong flex items-center justify-center\">\n {hasVideo ? <VideoOff className=\"w-8 h-8\" /> : <User className=\"w-8 h-8\" />}\n </div>\n )}\n </div>\n )}\n\n <div className=\"absolute bottom-2 left-2 flex items-center gap-1.5 px-2 py-1 rounded bg-video-overlay text-white text-xs\">\n {muted ? <MicOff className=\"w-3 h-3\" /> : <Mic className=\"w-3 h-3\" />}\n <span className=\"truncate max-w-35\">{name}</span>\n </div>\n </div>\n );\n}\n","import { useEffect, useRef } from \"react\";\nimport { cn } from \"../utils/cn\";\n\nexport interface VideoSurfaceProps {\n /**\n * Provider-specific mount callback. Receives the container element so\n * provider SDKs (Azure, Zoom, etc.) can attach their own video renderer.\n * Return an optional cleanup function.\n */\n attach: (el: HTMLDivElement) => void | (() => void);\n active?: boolean;\n mirrored?: boolean;\n className?: string;\n}\n\n/**\n * Provider-agnostic video tile surface. Owns the DOM slot; the caller wires\n * their SDK's renderer to it via `attach`.\n */\nexport function VideoSurface({ attach, active = true, mirrored = false, className }: VideoSurfaceProps) {\n const ref = useRef<HTMLDivElement>(null);\n\n useEffect(() => {\n if (!active || !ref.current) return;\n const cleanup = attach(ref.current);\n return () => {\n if (typeof cleanup === \"function\") cleanup();\n if (ref.current) ref.current.innerHTML = \"\";\n };\n }, [attach, active]);\n\n return (\n <div\n ref={ref}\n className={cn(\n \"w-full h-full bg-video-surface-strong overflow-hidden\",\n mirrored && \"[&>*]:scale-x-[-1]\",\n className,\n )}\n />\n );\n}\n","import React, { forwardRef } from 'react';\nimport { cn } from '../utils/cn';\n\nexport interface ButtonProps extends React.ButtonHTMLAttributes<HTMLButtonElement> {\n /**\n * The visual style variant of the button\n */\n variant?: 'primary' | 'secondary' | 'outline' | 'ghost' | 'destructive' | 'success' | 'warning' | 'danger-solid';\n\n /**\n * The size of the button\n */\n size?: 'xs' | 'sm' | 'md' | 'lg' | 'xl' | '2xl' | 'full';\n\n /**\n * Whether the button should take the full width of its container\n */\n fullWidth?: boolean;\n\n /**\n * Whether the button is in a loading state\n */\n loading?: boolean;\n\n /**\n * Icon to display before the button text\n */\n leftIcon?: React.ReactNode;\n\n /**\n * Icon to display after the button text\n */\n rightIcon?: React.ReactNode;\n\n /**\n * Whether the button should only display an icon (no text)\n */\n iconOnly?: boolean;\n\n /** `circle` is for a control that is only ever an icon: call answer/reject. */\n shape?: 'default' | 'circle';\n}\n\n/**\n * Variant styles — semantic tokens only, so dark mode needs no extra classes.\n * One primary button per view; everything else is secondary, ghost or a Link.\n */\nconst buttonVariants = {\n primary: 'bg-accent text-accent-fg hover:bg-accent-hover disabled:bg-surface-hover',\n secondary: 'bg-surface-sunk text-text-strong hover:bg-surface-hover disabled:bg-surface-hover',\n // No resting fill, so no disabled fill either — a greyed-out plate where\n // there was nothing reads as a different control, not as a disabled one.\n outline: 'border border-border text-text-strong hover:bg-surface-hover',\n ghost: 'text-text-muted hover:bg-surface-hover hover:text-text',\n destructive:\n 'border border-danger-border bg-danger-soft text-danger-fg hover:border-danger disabled:bg-surface-hover',\n // Solid status fills. Reserved for a control whose colour IS the answer —\n // an RSVP, answering or rejecting a call — not for ordinary emphasis.\n success: 'bg-success text-text-inverse hover:opacity-90 disabled:bg-surface-hover',\n warning: 'bg-warning text-text-inverse hover:opacity-90 disabled:bg-surface-hover',\n 'danger-solid': 'bg-danger text-text-inverse hover:opacity-90 disabled:bg-surface-hover',\n};\n\n/** Height comes from the shared control tokens so buttons line up with inputs. */\nconst buttonSizes = {\n xs: 'h-control-xs px-2 text-xs',\n sm: 'h-control-sm px-3 text-sm',\n md: 'h-control-md px-4 text-sm',\n lg: 'h-control-lg px-4 text-sm',\n xl: 'h-control-xl px-6 text-base',\n '2xl': 'h-control-2xl px-6 text-base',\n full: 'h-control-md px-4 text-sm',\n};\n\nconst iconOnlySizes = {\n xs: 'h-control-xs w-6',\n sm: 'h-control-sm w-7',\n md: 'h-control-md w-8',\n lg: 'h-control-lg w-9',\n xl: 'h-control-xl w-10',\n '2xl': 'h-control-2xl w-12',\n full: 'h-control-md w-8',\n};\n\n/**\n * Button component with theme integration and multiple variants\n *\n * @example\n * ```tsx\n * <Button variant=\"primary\" size=\"md\">Click me</Button>\n * <Button variant=\"outline\" leftIcon={<Icon name={Plus} />}>Add item</Button>\n * <Button iconOnly variant=\"ghost\" aria-label=\"Zoeken\">\n * <Icon name={Search} />\n * </Button>\n * ```\n */\nexport const Button = forwardRef<HTMLButtonElement, ButtonProps>(\n (\n {\n variant = 'primary',\n size = 'md',\n fullWidth = false,\n loading = false,\n leftIcon,\n rightIcon,\n iconOnly = false,\n shape = 'default',\n className,\n children,\n disabled,\n ...props\n },\n ref\n ) => {\n const isDisabled = disabled || loading;\n\n return (\n <button\n ref={ref}\n type=\"button\"\n className={cn(\n // font-medium, not semibold: in the design a button's label carries\n // the same weight as an emphasised nav item, and 600 at 12–13px\n // reads as a heavier control than the surrounding chrome.\n 'inline-flex shrink-0 items-center justify-center gap-2 cursor-pointer font-medium',\n shape === 'circle' ? 'rounded-full' : 'rounded-md',\n 'transition-colors duration-fast ease-out',\n 'focus-visible:outline-none focus-visible:focus-ring',\n 'disabled:cursor-not-allowed disabled:border-border-subtle',\n 'disabled:text-text-disabled',\n\n buttonVariants[variant],\n iconOnly ? iconOnlySizes[size] : buttonSizes[size],\n\n (fullWidth || size === 'full') && 'w-full',\n loading && 'cursor-wait',\n\n className\n )}\n disabled={isDisabled}\n aria-busy={loading || undefined}\n {...props}\n >\n {loading && (\n <span\n aria-hidden\n className=\"size-icon-md shrink-0 animate-spin rounded-full border-2 border-current border-t-transparent\"\n />\n )}\n\n {!loading && leftIcon && <span className=\"flex items-center justify-center shrink-0\">{leftIcon}</span>}\n\n {!iconOnly && children}\n\n {!loading && rightIcon && <span className=\"flex items-center justify-center shrink-0\">{rightIcon}</span>}\n\n {iconOnly && !loading && !leftIcon && !rightIcon && children}\n </button>\n );\n }\n);\n\nButton.displayName = 'Button';\n","import React from 'react';\nimport { cn } from '../utils/cn';\n\nexport interface ButtonGroupProps {\n /** Child buttons to group */\n children: React.ReactNode;\n /** Size of the button group */\n size?: 'xs' | 'sm' | 'md' | 'lg' | 'xl';\n /** Orientation of the button group */\n orientation?: 'horizontal' | 'vertical';\n /** Whether buttons should be attached (no gap) */\n attached?: boolean;\n /** Additional CSS classes */\n className?: string;\n}\n\n/**\n * ButtonGroup component for grouping related buttons\n */\nexport const ButtonGroup: React.FC<ButtonGroupProps> = ({\n children,\n size = 'md',\n orientation = 'horizontal',\n attached = true,\n className,\n}) => {\n const baseClasses = cn(\n 'inline-flex',\n {\n // Orientation\n 'flex-row': orientation === 'horizontal',\n 'flex-col': orientation === 'vertical',\n \n // Attached styling\n '[&>*:not(:first-child):not(:last-child)]:rounded-none': attached,\n '[&>*:first-child]:rounded-r-none': attached && orientation === 'horizontal',\n '[&>*:last-child]:rounded-l-none': attached && orientation === 'horizontal',\n '[&>*:first-child]:rounded-b-none': attached && orientation === 'vertical',\n '[&>*:last-child]:rounded-t-none': attached && orientation === 'vertical',\n \n // Borders for attached buttons\n '[&>*:not(:first-child)]:-ml-px': attached && orientation === 'horizontal',\n '[&>*:not(:first-child)]:-mt-px': attached && orientation === 'vertical',\n \n // Spacing for non-attached buttons\n 'gap-1': !attached && size === 'xs',\n 'gap-2': !attached && (size === 'sm' || size === 'md'),\n 'gap-3': !attached && (size === 'lg' || size === 'xl'),\n },\n className\n );\n\n return (\n <div className={baseClasses} role=\"group\">\n {children}\n </div>\n );\n}; ","import * as LucideIcons from 'lucide-react';\nimport React from 'react';\nimport { cn } from '../utils/cn';\n\n/**\n * Lucide icon by name, for icons that arrive as data rather than as an import —\n * a provider declaring `icon: \"MessageCircle\"` in its description, a menu entry\n * from a manifest. Accepts kebab-case, snake_case, spaced or PascalCase.\n *\n * Returns `undefined` for an unknown name so the caller can fall back; an app\n * naming an icon that does not exist should not blank out the surface.\n */\nexport function resolveLucideIcon(name: string | undefined): React.ComponentType<any> | undefined {\n if (!name) return undefined;\n const pascal = name\n .split(/[-_ ]/)\n .filter(Boolean)\n .map((part) => part.charAt(0).toUpperCase() + part.slice(1))\n .join('');\n const found = (LucideIcons as unknown as Record<string, unknown>)[pascal];\n return typeof found === 'function' || (typeof found === 'object' && found !== null)\n ? (found as React.ComponentType<any>)\n : undefined;\n}\n\nexport interface IconProps {\n /** Icon component from lucide-react or custom icon */\n icon: React.ComponentType<any>;\n /** Icon size */\n size?: 'xs' | 'sm' | 'md' | 'lg' | 'xl' | number;\n /** Icon color */\n color?: 'primary' | 'secondary' | 'accent' | 'success' | 'warning' | 'error' | 'info' | 'neutral' | 'current';\n /** Whether the icon should be clickable */\n clickable?: boolean;\n /** Click handler */\n onClick?: () => void;\n /** Additional CSS classes */\n className?: string;\n /** Accessibility label */\n 'aria-label'?: string;\n}\n\n/**\n * Icon — the only way icons enter the product. Always a lucide-react component;\n * never a unicode glyph, an emoji or an inline <svg> in feature code.\n *\n * Sizes follow the icon tokens: xs 12 · sm 14 (default in controls) · md 16 ·\n * lg 20 · xl 24.\n */\nconst colorMap: Record<NonNullable<IconProps['color']>, string> = {\n primary: 'text-text',\n secondary: 'text-text-muted',\n accent: 'text-accent',\n success: 'text-success-fg',\n warning: 'text-warning-fg',\n error: 'text-danger-fg',\n info: 'text-info-fg',\n neutral: 'text-text-subtle',\n current: 'text-current',\n};\n\nexport const Icon: React.FC<IconProps> = ({\n icon: IconComponent,\n size = 'md',\n color = 'current',\n clickable = false,\n onClick,\n className,\n 'aria-label': ariaLabel,\n ...props\n}) => {\n const sizeValue = typeof size === 'number' ? size : getSizeValue(size);\n\n const iconClasses = cn(\n 'inline-block shrink-0',\n colorMap[color],\n clickable && [\n 'cursor-pointer rounded-sm transition-opacity duration-fast ease-out hover:opacity-80',\n 'focus-visible:outline-none focus-visible:focus-ring',\n ],\n className\n );\n\n const iconProps = {\n size: sizeValue,\n strokeWidth: 2,\n className: iconClasses,\n onClick: clickable ? onClick : undefined,\n 'aria-label': ariaLabel,\n 'aria-hidden': ariaLabel ? undefined : true,\n role: clickable ? 'button' : undefined,\n tabIndex: clickable ? 0 : undefined,\n onKeyDown: clickable\n ? (e: React.KeyboardEvent) => {\n if (e.key === 'Enter' || e.key === ' ') {\n e.preventDefault();\n onClick?.();\n }\n }\n : undefined,\n ...props,\n };\n\n return <IconComponent {...iconProps} />;\n};\n\nfunction getSizeValue(size: 'xs' | 'sm' | 'md' | 'lg' | 'xl'): number {\n const sizeMap = {\n xs: 12,\n sm: 14,\n md: 16,\n lg: 20,\n xl: 24,\n };\n\n return sizeMap[size];\n}\n","import React, { useEffect, useRef, useState } from \"react\";\nimport { cn } from \"../utils/cn\";\nimport { useAnchoredPosition } from \"../utils/useAnchoredPosition\";\n\nexport interface PopoverProps {\n /** Element that toggles the popover */\n trigger: React.ReactNode;\n /**\n * Panel content. Pass a function to receive a `close` callback so rows can\n * dismiss the popover after acting.\n */\n children: React.ReactNode | ((close: () => void) => React.ReactNode);\n /** Panel placement relative to the trigger. Flips when there is no room. */\n placement?: \"bottom-start\" | \"bottom-end\" | \"top-start\" | \"top-end\";\n /** Additional CSS classes for the panel */\n className?: string;\n /**\n * Layout classes for the wrapper around the trigger. Needed when the trigger\n * has to fill a positioned box — a calendar event in a week grid, say —\n * because the wrapper is `inline-flex` by default.\n */\n rootClassName?: string;\n /** Layout classes for the trigger button itself. */\n triggerClassName?: string;\n /** Whether the trigger is disabled */\n disabled?: boolean;\n /**\n * Accessible name for the trigger button. Needed when the trigger is\n * icon-only, since the panel content is not announced by the trigger.\n */\n triggerLabel?: string;\n}\n\n/**\n * Generic popover with click-outside / Escape dismissal. The panel is\n * `position: fixed` (computed from the trigger) so it escapes any\n * overflow-hidden or rounded-card ancestor instead of being clipped.\n */\nexport const Popover: React.FC<PopoverProps> = ({\n trigger,\n children,\n placement = \"bottom-start\",\n className,\n rootClassName,\n triggerClassName,\n disabled = false,\n triggerLabel,\n}) => {\n const [isOpen, setIsOpen] = useState(false);\n const rootRef = useRef<HTMLDivElement>(null);\n const triggerRef = useRef<HTMLButtonElement>(null);\n // Shared with Select, DatePicker and Dropdown: flips up when the trigger sits\n // near the bottom, caps the height to the space available, and re-measures on\n // scroll so the panel keeps tracking its trigger.\n const panelStyle = useAnchoredPosition(isOpen, triggerRef, { placement });\n\n useEffect(() => {\n if (!isOpen) return;\n const onDown = (event: MouseEvent) => {\n if (rootRef.current && !rootRef.current.contains(event.target as Node)) {\n setIsOpen(false);\n }\n };\n const onEsc = (event: KeyboardEvent) => {\n if (event.key === \"Escape\") setIsOpen(false);\n };\n document.addEventListener(\"mousedown\", onDown);\n document.addEventListener(\"keydown\", onEsc);\n return () => {\n document.removeEventListener(\"mousedown\", onDown);\n document.removeEventListener(\"keydown\", onEsc);\n };\n }, [isOpen]);\n\n const handleToggle = (event: React.MouseEvent<HTMLButtonElement>) => {\n event.stopPropagation();\n if (disabled) return;\n setIsOpen((open) => !open);\n };\n\n const close = () => setIsOpen(false);\n\n return (\n <div ref={rootRef} className={cn(\"relative inline-flex\", rootClassName)}>\n <button\n ref={triggerRef}\n type=\"button\"\n onClick={handleToggle}\n disabled={disabled}\n aria-label={triggerLabel}\n aria-expanded={isOpen}\n className={cn(\n \"inline-flex items-center\",\n disabled && \"cursor-not-allowed opacity-50\",\n triggerClassName,\n )}\n >\n {trigger}\n </button>\n\n {isOpen && (\n <div\n className={cn(\n // overflow-y-auto pairs with the hook's max-height: without it a\n // panel taller than the space available is simply cut off.\n \"fixed z-overlay overflow-y-auto rounded-lg border border-border bg-surface shadow-overlay\",\n className,\n )}\n style={panelStyle}\n >\n {typeof children === \"function\" ? children(close) : children}\n </div>\n )}\n </div>\n );\n};\n","import { ChevronDown, X } from \"lucide-react\";\nimport React from \"react\";\nimport { Icon } from \"../content/Icon\";\nimport { Popover } from \"../overlays/Popover\";\nimport { cn } from \"../utils/cn\";\n\nexport interface FilterChipProps {\n /** Chip text (e.g. \"Status\", or \"Status: Open\" when a value is set). */\n label: React.ReactNode;\n /** Leading icon, before the label. */\n icon?: React.ReactNode;\n /**\n * Meaning carried by the chip's own value — a priority, a state. Applies to\n * the resting chip; `active` still wins, because \"you picked this\" outranks\n * \"this is urgent\".\n */\n tone?: \"none\" | \"default\" | \"muted\" | \"outline\" | \"warning\" | \"danger\";\n /**\n * `rect` is the filter-bar shape — the same 9px corner as a button, so a\n * chip and a button in one toolbar line up. `pill` is for a chip that reads\n * as a tag rather than a control.\n */\n shape?: \"pill\" | \"rect\";\n /** `md` is the default control height; `sm` for a dense toolbar. */\n size?: \"sm\" | \"md\";\n /** Selected/active — renders the filled dark treatment. */\n active?: boolean;\n /** Show a trailing caret (opens a menu the consumer wires with Dropdown/Popover). */\n caret?: boolean;\n /**\n * Menu panel for a chip that opens its own popover. Receives a `close`\n * callback so a row can dismiss the panel after picking. Without it the chip\n * is purely presentational and `onClick` is yours to wire.\n */\n menu?: (close: () => void) => React.ReactNode;\n /** Panel classes, when `menu` is set. */\n menuClassName?: string;\n /** Open a value clear affordance (✕) — only shown when `active`. */\n onClear?: () => void;\n /** Accessible name for the clear affordance. */\n clearLabel?: string;\n onClick?: () => void;\n /** Native tooltip, for a chip whose label is truncated or abbreviated. */\n title?: string;\n className?: string;\n}\n\n/**\n * Resting fills. A filter bar on the white card uses sunk plates — an outlined\n * row of chips reads as a row of empty inputs at this size. `outline` is the\n * exception, for a bar that already contains a sunk plate (the table toolbar,\n * where the search field is the sunk one): there a second sunk fill beside it\n * makes the two read as one smeared control.\n */\nconst tones: Record<NonNullable<FilterChipProps[\"tone\"]>, string> = {\n none: \"hover:bg-surface-sunk hover:text-text\",\n default: \"bg-surface-sunk text-text-muted hover:text-text\",\n muted: \"bg-surface-sunk text-text-subtle hover:text-text\",\n outline:\n \"text-text-muted ring-1 ring-inset ring-border-strong hover:bg-surface-hover hover:text-text\",\n warning: \"bg-warning-soft text-warning-fg\",\n danger: \"bg-danger-soft text-danger-fg\",\n};\n\ntype ChipShape = NonNullable<FilterChipProps[\"shape\"]>;\n\nconst chipShell = (opts: {\n active?: boolean;\n tone?: NonNullable<FilterChipProps[\"tone\"]>;\n shape?: ChipShape;\n size?: NonNullable<FilterChipProps[\"size\"]>;\n className?: string;\n}) =>\n cn(\n // A button's default cursor is an arrow, so it has to be asked for.\n \"inline-flex cursor-pointer select-none items-center text-sm font-medium\",\n opts.size === \"sm\" ? \"h-control-sm\" : \"h-control-md\",\n \"transition-colors duration-fast ease-out\",\n opts.shape === \"pill\" ? \"rounded-full\" : \"rounded-md\",\n // Picking a value outranks whatever the value happens to mean.\n opts.active ? \"bg-info-soft text-info-fg\" : tones[opts.tone ?? \"default\"],\n opts.className,\n );\n\nconst chipBody = (opts: { shape?: ChipShape; withClear?: boolean }) =>\n cn(\n \"inline-flex items-center gap-1.5 pl-3\",\n opts.shape === \"pill\" ? \"rounded-full\" : \"rounded-md\",\n opts.withClear ? \"pr-1.5\" : \"pr-3\",\n \"focus-visible:outline-none focus-visible:focus-ring\",\n );\n\n\n/**\n * Filter chip — the inbox filter bar, the table toolbar, and the thread\n * priority/assign/inbox/tags menus. Presentational by default (the consumer\n * wires the menu with `Dropdown`/`Popover` and `onClick`); pass `menu` and the\n * chip opens its own popover instead, which is the only way to get a clear\n * button on a menu chip — a `<FilterChip>` used as someone else's trigger\n * would nest a button inside a button.\n *\n * @example\n * ```tsx\n * <FilterChip label={status ? `Status: ${status}` : \"Status\"} caret\n * active={!!status} onClear={() => setStatus(null)}\n * menu={(close) => <StatusList onPick={(s) => { setStatus(s); close(); }} />} />\n * ```\n */\nexport function FilterChip({\n label,\n icon,\n tone = \"default\",\n shape = \"rect\",\n size = \"md\",\n active = false,\n caret = false,\n menu,\n menuClassName,\n onClear,\n clearLabel = \"Filter wissen\",\n onClick,\n title,\n className,\n}: FilterChipProps) {\n const showClear = active && Boolean(onClear);\n\n // The chip and its clear affordance are two separate controls, so the shell is\n // a plain span: a <button> may not contain another <button>. Without a clear,\n // there is only one control and the shell collapses onto it.\n const radius = shape === \"pill\" ? \"rounded-full\" : \"rounded-md\";\n\n const shell = chipShell({ active, tone, shape, size, className });\n\n const body = (\n <>\n {icon}\n {label}\n {caret && <Icon icon={ChevronDown} size=\"xs\" />}\n </>\n );\n\n const bodyClasses = chipBody({ shape, withClear: showClear });\n\n const clearButton = showClear && (\n <button\n type=\"button\"\n aria-label={clearLabel}\n onClick={onClear}\n className={cn(\"inline-flex h-full items-center pr-3 focus-visible:outline-none focus-visible:focus-ring\", radius)}\n >\n <Icon icon={X} size=\"xs\" />\n </button>\n );\n\n if (menu) {\n return (\n <span className={shell} title={title}>\n <Popover\n trigger={body}\n // Both heights are needed: the shell has the definite height, so the\n // trigger only fills the plate if the wrapper passes it down.\n rootClassName=\"h-full\"\n triggerClassName={cn(bodyClasses, \"h-full\")}\n className={cn(\"min-w-menu p-1.5\", menuClassName)}\n >\n {menu}\n </Popover>\n {clearButton}\n </span>\n );\n }\n\n if (!showClear) {\n return (\n <button type=\"button\" title={title} onClick={onClick} className={cn(shell, bodyClasses)}>\n {body}\n </button>\n );\n }\n\n return (\n <span className={shell} title={title}>\n <button type=\"button\" onClick={onClick} className={bodyClasses}>\n {body}\n </button>\n {clearButton}\n </span>\n );\n}\n","import React from 'react';\nimport { ExternalLink } from 'lucide-react';\nimport { cn } from '../utils/cn';\n\nexport interface LinkProps extends React.AnchorHTMLAttributes<HTMLAnchorElement> {\n /** Link variant */\n variant?: 'default' | 'subtle' | 'underline' | 'button';\n /** Link size */\n size?: 'xs' | 'sm' | 'md' | 'lg' | 'xl';\n /** Color theme */\n color?: 'primary' | 'secondary' | 'accent' | 'success' | 'warning' | 'error' | 'info' | 'neutral';\n /** Whether the link is disabled */\n disabled?: boolean;\n /** Whether to show external link icon */\n external?: boolean;\n /** Additional CSS classes */\n className?: string;\n /** Child content */\n children: React.ReactNode;\n}\n\n/** Same steps as Text: xs 11 · sm 12 · md 13 · lg 14 · xl 16. */\nconst sizeMap: Record<NonNullable<LinkProps['size']>, string> = {\n xs: 'text-xs',\n sm: 'text-sm',\n md: 'text-base',\n lg: 'text-md',\n xl: 'text-lg',\n};\n\nconst colorMap: Record<NonNullable<LinkProps['color']>, string> = {\n primary: 'text-text hover:text-info-fg hover:underline',\n info: 'text-info-fg hover:underline',\n secondary: 'text-text-muted hover:text-text',\n neutral: 'text-text-muted hover:text-text',\n accent: 'text-accent hover:underline',\n success: 'text-success-fg hover:underline',\n warning: 'text-warning-fg hover:underline',\n error: 'text-danger-fg hover:underline',\n};\n\n/** `variant=\"button\"` uses the soft surface of the matching status token. */\nconst buttonBackgroundMap: Record<NonNullable<LinkProps['color']>, string> = {\n primary: 'bg-accent-soft',\n accent: 'bg-accent-soft',\n secondary: 'bg-surface-hover',\n neutral: 'bg-surface-hover',\n success: 'bg-success-soft',\n warning: 'bg-warning-soft',\n error: 'bg-danger-soft',\n info: 'bg-info-soft',\n};\n\n/**\n * Link component with theme integration and accessibility features.\n * Use for navigation; use Button for actions.\n */\nexport const Link: React.FC<LinkProps> = ({\n variant = 'default',\n size = 'md',\n color = 'primary',\n disabled = false,\n external = false,\n className,\n children,\n href,\n target,\n rel,\n ...props\n}) => {\n const isExternal =\n external || (href && (href.startsWith('http') || href.startsWith('mailto:')));\n\n const baseClasses = cn(\n 'inline-flex items-center gap-1 underline-offset-2',\n 'transition-colors duration-fast ease-out',\n 'focus-visible:outline-none focus-visible:focus-ring',\n\n sizeMap[size],\n !disabled && colorMap[color],\n\n variant === 'subtle' && 'no-underline opacity-70 hover:opacity-100',\n variant === 'underline' && 'underline decoration-1 hover:decoration-2',\n variant === 'button' && [\n 'h-control-md rounded-md px-3 font-semibold no-underline hover:no-underline',\n buttonBackgroundMap[color],\n ],\n\n disabled && 'pointer-events-none cursor-not-allowed text-text-disabled opacity-50',\n\n className\n );\n\n const linkProps = {\n ...props,\n href: disabled ? undefined : href,\n target: isExternal ? '_blank' : target,\n rel: isExternal ? 'noopener noreferrer' : rel,\n 'aria-disabled': disabled || undefined,\n };\n\n return (\n <a className={baseClasses} {...linkProps}>\n {children}\n {isExternal && <ExternalLink className=\"size-icon-sm shrink-0\" aria-hidden />}\n </a>\n );\n};\n","import React from \"react\";\nimport { cn } from \"../utils/cn\";\n\nexport interface SegmentedOption<T extends string> {\n value: T;\n label: React.ReactNode;\n /**\n * Accessible name and tooltip, for a segment whose label is an icon. Without\n * it an icon-only segment announces as an empty tab.\n */\n title?: string;\n}\n\nexport interface SegmentedToggleProps<T extends string> {\n options: SegmentedOption<T>[];\n value: T;\n onChange: (value: T) => void;\n /** Control height. */\n size?: \"sm\" | \"md\";\n /**\n * Track fill. `sunk` reads against the white card; use `track` when the\n * toggle itself sits on a sunk plane, where `sunk` on `sunk` is invisible.\n */\n tone?: \"sunk\" | \"track\";\n /** Fill the container and split it evenly — a toggle that heads a column. */\n fullWidth?: boolean;\n className?: string;\n /** Accessible group label. */\n \"aria-label\"?: string;\n}\n\n/** Track height stays one step below the equivalent Button so it nests in toolbars. */\nconst sizes = {\n sm: \"h-control-sm px-3 text-sm\",\n md: \"h-control-md px-3 text-sm\",\n};\n\n/**\n * Segmented toggle (focus \"Feed / Eén tegelijk\", tasks \"Mijn / Mijn teams\").\n * Track = surface-sunk, active segment = a raised white plate — the same\n * \"lifted off the plane behind it\" language as the active nav item.\n *\n * @example\n * ```tsx\n * <SegmentedToggle\n * value={layout}\n * onChange={setLayout}\n * options={[{ value: \"feed\", label: \"Feed\" }, { value: \"one\", label: \"Eén tegelijk\" }]}\n * />\n * ```\n */\nexport function SegmentedToggle<T extends string>({\n options,\n value,\n onChange,\n size = \"sm\",\n tone = \"sunk\",\n fullWidth = false,\n className,\n \"aria-label\": ariaLabel,\n}: SegmentedToggleProps<T>) {\n return (\n <div\n role=\"tablist\"\n aria-label={ariaLabel}\n className={cn(\n \"gap-0.5 rounded-md p-0.5\",\n tone === \"track\" ? \"bg-surface-track\" : \"bg-surface-sunk\",\n fullWidth ? \"flex w-full\" : \"inline-flex\",\n className,\n )}\n >\n {options.map((opt) => {\n const active = opt.value === value;\n return (\n <button\n key={opt.value}\n role=\"tab\"\n aria-selected={active}\n aria-label={opt.title}\n title={opt.title}\n type=\"button\"\n onClick={() => onChange(opt.value)}\n className={cn(\n \"inline-flex cursor-pointer items-center justify-center gap-1.5 rounded-sm\",\n \"transition-colors duration-fast ease-out\",\n \"focus-visible:outline-none focus-visible:focus-ring\",\n fullWidth && \"min-w-0 flex-1\",\n sizes[size],\n active ? \"bg-surface text-text font-medium shadow-sm\" : \"text-text-muted hover:text-text\",\n )}\n >\n {opt.label}\n </button>\n );\n })}\n </div>\n );\n}\n","import { ChevronDown } from \"lucide-react\";\nimport React from \"react\";\nimport { Popover } from \"../overlays/Popover\";\nimport { cn } from \"../utils/cn\";\nimport { Button } from \"./Button\";\n\nexport interface SplitButtonOption {\n id: string;\n label: string;\n onClick: () => void;\n variant?: \"default\" | \"destructive\";\n /** Optioneel icoon vóór het label in het menu. */\n icon?: React.ReactNode;\n}\n\nexport interface SplitButtonProps {\n label: string;\n onClick: () => void;\n variant?: \"primary\" | \"secondary\" | \"outline\";\n size?: \"sm\" | \"md\";\n icon?: React.ReactNode;\n options: SplitButtonOption[];\n disabled?: boolean;\n /** Spinner in de primaire helft; blokkeert beide helften. */\n loading?: boolean;\n /**\n * Waar het optie-menu opent. Gebruik een `top-*` placement wanneer de knop\n * onderaan zijn container staat (bv. een sticky verzendbalk).\n */\n menuPlacement?: \"bottom-end\" | \"bottom-start\" | \"top-end\" | \"top-start\";\n /** Accessible naam voor de chevron-knop. */\n menuLabel?: string;\n}\n\n/** Zelfde varianttokens als Button, zodat beide helften één knop lijken. */\nconst variantStyles = {\n primary: \"bg-accent text-accent-fg hover:bg-accent-hover\",\n secondary: \"border border-border bg-surface text-text hover:bg-surface-hover\",\n outline: \"border border-accent-border text-accent hover:bg-accent-soft\",\n};\n\nconst chevronSizes = {\n sm: \"h-control-sm w-7\",\n md: \"h-control-md w-8\",\n};\n\n/**\n * Knop met een primaire actie plus een chevron-menu voor varianten daarvan.\n * De primaire helft is een gewone `Button` (zelfde varianten/loading-gedrag);\n * het menu loopt via `Popover`, dus het is `position: fixed` en wordt niet\n * geklipt door een scrollende of overflow-hidden voorouder.\n *\n * Zonder opties rendert dit precies een `Button` — geen chevron.\n */\nexport function SplitButton({\n label,\n onClick,\n variant = \"primary\",\n size = \"md\",\n icon,\n options,\n disabled = false,\n loading = false,\n menuPlacement = \"bottom-end\",\n menuLabel = \"More options\",\n}: SplitButtonProps) {\n const isDisabled = disabled || loading;\n const hasMenu = options.length > 0;\n\n return (\n // De scheiding tussen beide helften is een kier in de vulling, niet een\n // lijn: bij een ink-gevulde knop leest 2px als een spleet. 1px is genoeg\n // om te zien dat het twee doelen zijn. De omrande varianten hebben hun\n // eigen randen al en houden de helften tegen elkaar.\n <div className={cn(\"inline-flex items-center\", variant === \"primary\" && \"gap-px\")}>\n <Button\n variant={variant}\n size={size}\n onClick={onClick}\n disabled={disabled}\n loading={loading}\n leftIcon={icon}\n className={cn(hasMenu && \"rounded-r-none\")}\n >\n {label}\n </Button>\n {hasMenu && (\n <Popover\n placement={menuPlacement}\n disabled={isDisabled}\n triggerLabel={menuLabel}\n className=\"min-w-menu py-1\"\n trigger={\n <span\n aria-hidden=\"true\"\n className={cn(\n \"inline-flex items-center justify-center rounded-md rounded-l-none\",\n \"transition-colors duration-fast ease-out\",\n variantStyles[variant],\n chevronSizes[size],\n isDisabled && \"cursor-not-allowed opacity-50\",\n )}\n >\n <ChevronDown className=\"size-icon-md\" />\n </span>\n }\n >\n {(close) => (\n <>\n {options.map((option) => (\n <button\n key={option.id}\n type=\"button\"\n onClick={() => {\n option.onClick();\n close();\n }}\n className={cn(\n \"flex w-full items-center gap-2 px-3 py-1.5 text-left text-sm\",\n \"transition-colors duration-fast ease-out\",\n \"focus-visible:outline-none focus-visible:focus-ring\",\n option.variant === \"destructive\"\n ? \"text-danger-fg hover:bg-danger-soft\"\n : \"text-text hover:bg-surface-hover\",\n )}\n >\n {option.icon && (\n <span className=\"shrink-0\">{option.icon}</span>\n )}\n {option.label}\n </button>\n ))}\n </>\n )}\n </Popover>\n )}\n </div>\n );\n}\n","import React, { forwardRef } from 'react';\nimport { cn } from '../utils/cn';\n\nexport interface CheckboxProps extends Omit<React.InputHTMLAttributes<HTMLInputElement>, 'size'> {\n /**\n * The label for the checkbox\n */\n label?: string;\n\n /**\n * Helper text to display below the checkbox\n */\n helperText?: string;\n\n /**\n * Error message to display when the checkbox is invalid\n */\n error?: string;\n\n /**\n * The size of the checkbox\n */\n size?: 'sm' | 'md' | 'lg' | 'full';\n\n /**\n * Whether the checkbox is in an indeterminate state\n */\n indeterminate?: boolean;\n\n /**\n * Additional class name for the container\n */\n containerClassName?: string;\n\n /**\n * Additional class name for the label\n */\n labelClassName?: string;\n}\n\n/** The box grows with the field size, so a checkbox row reads as the same\n * weight as the inputs beside it instead of a small mark floating next to them. */\nconst checkboxSizes = {\n sm: 'size-checkbox-sm',\n md: 'size-checkbox',\n lg: 'size-checkbox-lg',\n full: 'size-checkbox',\n};\n\n/** Row height matches the control tokens so a checkbox lines up in a form. */\nconst rowSizes = {\n sm: 'min-h-control-sm',\n md: 'min-h-control-md',\n lg: 'min-h-control-lg',\n full: 'min-h-control-md',\n};\n\n/**\n * `full` means full width, not large: it mirrors `md` here the same way\n * `checkboxSizes` and `rowSizes` do, and the same way every other control in\n * the kit keeps `text-base` at `full`. It used to read `text-md`, which made\n * the label a step bigger than every field beside it — every Form passes\n * `size=\"full\"`, so that hit each checkbox in every form in the product.\n */\nconst labelSizes = {\n sm: 'text-sm',\n md: 'text-base',\n lg: 'text-md',\n full: 'text-base',\n};\n\n/**\n * Checkbox component with theme integration.\n *\n * Uses the native input with `accent-color`, so the checked fill is the accent\n * token and dark mode needs no extra classes.\n *\n * @example\n * ```tsx\n * <Checkbox label=\"Voorwaarden accepteren\" />\n * <Checkbox label=\"Alles selecteren\" indeterminate />\n * ```\n */\nexport const Checkbox = forwardRef<HTMLInputElement, CheckboxProps>(\n (\n {\n label,\n helperText,\n error,\n size = 'md',\n indeterminate = false,\n containerClassName,\n labelClassName,\n className,\n id,\n ...props\n },\n ref\n ) => {\n const reactId = React.useId();\n const checkboxId = id || `checkbox-${reactId}`;\n const hasError = Boolean(error);\n const innerRef = React.useRef<HTMLInputElement | null>(null);\n\n // Keep the forwarded ref and the internal one in sync so `indeterminate`\n // works whether or not the consumer passes a ref.\n const setRefs = React.useCallback(\n (node: HTMLInputElement | null) => {\n innerRef.current = node;\n if (typeof ref === 'function') ref(node);\n else if (ref && typeof ref === 'object') {\n (ref as React.MutableRefObject<HTMLInputElement | null>).current = node;\n }\n },\n [ref]\n );\n\n React.useEffect(() => {\n if (innerRef.current) innerRef.current.indeterminate = indeterminate;\n }, [indeterminate]);\n\n return (\n <div className={cn('flex flex-col', containerClassName)}>\n <div className={cn('flex items-center gap-3', rowSizes[size])}>\n <input\n ref={setRefs}\n id={checkboxId}\n type=\"checkbox\"\n aria-invalid={hasError || undefined}\n className={cn(\n // radius-xs (5px): its own step on the scale. At 16px the 9px\n // button radius reads as a circle and the 7px chip radius still\n // rounds the corners away — a checkbox has to stay a square you\n // can aim at, with the corner just knocked off.\n 'shrink-0 rounded-xs border accent-accent',\n 'transition-colors duration-fast ease-out',\n 'focus-visible:outline-none focus-visible:focus-ring',\n 'disabled:cursor-not-allowed disabled:bg-surface-hover',\n\n checkboxSizes[size],\n hasError ? 'border-danger-border' : 'border-border-strong',\n\n className\n )}\n {...props}\n />\n\n {label && (\n <div className=\"flex-1\">\n <label\n htmlFor={checkboxId}\n className={cn(\n 'cursor-pointer',\n hasError ? 'text-danger-fg' : 'text-text',\n labelSizes[size],\n labelClassName\n )}\n >\n {label}\n </label>\n\n {helperText && !error && (\n <p className=\"mt-0.5 text-xs text-text-subtle\">{helperText}</p>\n )}\n </div>\n )}\n </div>\n\n {error && <p className=\"mt-1 text-xs text-danger-fg\">{error}</p>}\n </div>\n );\n }\n);\n\nCheckbox.displayName = 'Checkbox';\n","import React from 'react';\nimport { cn } from '../utils/cn';\n\nexport interface TextProps {\n /** Text variant */\n variant?: 'body' | 'caption' | 'label' | 'code';\n /** Text size */\n size?: 'xs' | 'sm' | 'md' | 'lg' | 'xl';\n /** Font weight */\n weight?: 'light' | 'normal' | 'medium' | 'semibold' | 'bold';\n /** Text color */\n color?: 'primary' | 'secondary' | 'accent' | 'success' | 'warning' | 'error' | 'info' | 'neutral' | 'current' | 'muted';\n /** Text alignment */\n align?: 'left' | 'center' | 'right' | 'justify';\n /** Whether to truncate text with ellipsis */\n truncate?: boolean;\n /** Whether text should be italic */\n italic?: boolean;\n /** Whether text should be underlined */\n underline?: boolean;\n /** Line height */\n lineHeight?: 'tight' | 'normal' | 'relaxed';\n /** HTML element to render */\n as?: 'p' | 'span' | 'div' | 'code' | 'pre';\n /** Additional CSS classes */\n className?: string;\n /** Child content */\n children: React.ReactNode;\n}\n\n/**\n * Text — every copy string in the product goes through this component.\n *\n * Size maps onto the token type scale (tokens.css):\n * xs 11 · sm 12 · md 13 (body) · lg 14 (long-form) · xl 16\n * Anything above 16px is a Heading, not Text.\n */\nconst sizeMap: Record<NonNullable<TextProps['size']>, string> = {\n xs: 'text-xs',\n sm: 'text-sm',\n md: 'text-base',\n lg: 'text-md',\n xl: 'text-lg',\n};\n\nconst weightMap: Record<NonNullable<TextProps['weight']>, string> = {\n light: 'font-normal',\n normal: 'font-normal',\n medium: 'font-medium',\n semibold: 'font-semibold',\n bold: 'font-bold',\n};\n\n/** Semantic colour tokens — these flip in dark mode, so no `dark:` variants. */\nconst colorMap: Record<NonNullable<TextProps['color']>, string> = {\n primary: 'text-text',\n secondary: 'text-text-muted',\n accent: 'text-accent',\n success: 'text-success-fg',\n warning: 'text-warning-fg',\n error: 'text-danger-fg',\n info: 'text-info-fg',\n neutral: 'text-text',\n current: 'text-current',\n muted: 'text-text-subtle',\n};\n\nconst alignMap: Record<NonNullable<TextProps['align']>, string> = {\n left: 'text-left',\n center: 'text-center',\n right: 'text-right',\n justify: 'text-justify',\n};\n\nconst lineHeightMap: Record<NonNullable<TextProps['lineHeight']>, string> = {\n tight: 'leading-tight',\n normal: 'leading-normal',\n relaxed: 'leading-relaxed',\n};\n\nexport const Text: React.FC<TextProps> = ({\n variant = 'body',\n size = 'md',\n weight = 'normal',\n color = 'current',\n align = 'left',\n truncate = false,\n italic = false,\n underline = false,\n lineHeight = 'normal',\n as,\n className,\n children,\n ...props\n}) => {\n const Tag = (as || getDefaultElement(variant)) as keyof React.JSX.IntrinsicElements;\n\n const isCaption = variant === 'caption';\n const isLabel = variant === 'label';\n const isCode = variant === 'code';\n\n const textClasses = cn(\n 'font-sans',\n\n // Variant — caption and label pin their own size/weight\n isCaption && 'text-xs text-text-subtle',\n isLabel && 'text-xs font-semibold uppercase tracking-label text-text-subtle',\n isCode && 'font-mono text-sm rounded-sm bg-surface-hover px-1 py-0.5',\n\n // Size — only where the variant does not pin it\n !isCaption && !isLabel && !isCode && sizeMap[size],\n\n // Weight — label owns its weight\n !isLabel && weightMap[weight],\n\n colorMap[color],\n alignMap[align],\n\n // Line height only overrides the body variant\n variant === 'body' && lineHeightMap[lineHeight],\n\n italic && 'italic',\n underline && 'underline',\n truncate && 'truncate',\n\n className\n );\n\n return (\n <Tag className={textClasses} {...props}>\n {children}\n </Tag>\n );\n};\n\nfunction getDefaultElement(variant: TextProps['variant']): string {\n const elementMap: Record<NonNullable<TextProps['variant']>, string> = {\n body: 'p',\n caption: 'span',\n label: 'span',\n code: 'code',\n };\n\n return elementMap[variant!] || 'p';\n}\n","import React, { useRef, useState } from \"react\";\nimport { Button } from \"../action/Button\";\nimport { Text } from \"../typography/Text\";\nimport { cn } from \"../utils/cn\";\n\nexport interface ImageFieldProps {\n label?: string;\n /** Current value as a base64 data URI, or undefined when empty. */\n value?: string;\n onChange: (value: string | undefined) => void;\n /** Longest side after downscaling. */\n maxDimension?: number;\n /**\n * Ceiling for the encoded result. The server checks this too — this one is\n * here so the user finds out before saving, not so the rule is enforced.\n */\n maxBytes?: number;\n /** Preview box shape. */\n aspect?: \"square\" | \"wide\";\n helperText?: React.ReactNode;\n disabled?: boolean;\n className?: string;\n chooseLabel?: string;\n removeLabel?: string;\n /** Shown when the picked file is still too large after downscaling. */\n tooLargeLabel?: string;\n}\n\n/**\n * Pick an image and keep it inline as a base64 data URI.\n *\n * For the small brand assets that live on a row rather than in the storage app\n * — an organisation logo, a help centre favicon. Not for content: an article\n * image belongs in storage, once storage can serve a public URL.\n *\n * The canvas downscale is a courtesy, not a limit. The same ceiling is enforced\n * server-side by `assertInlineImage`, because anyone can call the API without\n * going through this field.\n */\nexport function ImageField({\n label,\n value,\n onChange,\n maxDimension = 256,\n maxBytes,\n aspect = \"square\",\n helperText,\n disabled,\n className,\n chooseLabel = \"Choose\",\n removeLabel = \"Remove\",\n tooLargeLabel = \"That image is too large.\",\n}: ImageFieldProps) {\n const inputRef = useRef<HTMLInputElement>(null);\n const [error, setError] = useState<string | null>(null);\n\n const handleSelect = async (file?: File) => {\n if (!file) return;\n setError(null);\n const encoded = await downscaleToDataUri(file, maxDimension);\n if (maxBytes && approximateBytes(encoded) > maxBytes) {\n setError(tooLargeLabel);\n return;\n }\n onChange(encoded);\n };\n\n return (\n <div className={cn(\"flex flex-col gap-1.5\", className)}>\n {label && <span className=\"text-sm font-medium text-text\">{label}</span>}\n\n <div className=\"flex items-center gap-4\">\n <div\n className={cn(\n \"flex items-center justify-center overflow-hidden rounded-md border border-border bg-surface-sunk\",\n aspect === \"square\" ? \"h-16 w-16\" : \"h-16 w-28\",\n )}\n >\n {value ? (\n <img src={value} alt=\"\" className=\"h-full w-full object-contain\" />\n ) : (\n <Text variant=\"caption\" color=\"muted\">\n —\n </Text>\n )}\n </div>\n\n <div className=\"flex flex-col gap-2\">\n <div className=\"flex gap-2\">\n <Button\n type=\"button\"\n variant=\"secondary\"\n disabled={disabled}\n onClick={() => inputRef.current?.click()}\n >\n {chooseLabel}\n </Button>\n {value && (\n <Button\n type=\"button\"\n variant=\"ghost\"\n disabled={disabled}\n onClick={() => {\n setError(null);\n onChange(undefined);\n }}\n >\n {removeLabel}\n </Button>\n )}\n </div>\n {(error || helperText) && (\n <Text variant=\"caption\" color={error ? \"error\" : \"muted\"}>\n {error ?? helperText}\n </Text>\n )}\n </div>\n </div>\n\n <input\n ref={inputRef}\n type=\"file\"\n accept=\"image/png,image/jpeg,image/webp\"\n className=\"hidden\"\n onChange={(e) => void handleSelect(e.target.files?.[0])}\n />\n </div>\n );\n}\n\n/** Roughly how many bytes a data URI's payload decodes to. */\nexport function approximateBytes(dataUri: string): number {\n const base64 = dataUri.slice(dataUri.indexOf(\",\") + 1);\n const padding = base64.endsWith(\"==\") ? 2 : base64.endsWith(\"=\") ? 1 : 0;\n return Math.floor((base64.length * 3) / 4) - padding;\n}\n\n/** Read a file, shrink it to `maxDimension` on a canvas, return a PNG data URI. */\nfunction downscaleToDataUri(file: File, maxDimension: number): Promise<string> {\n return new Promise((resolve, reject) => {\n const reader = new FileReader();\n reader.onload = () => {\n const img = new Image();\n img.onload = () => {\n const scale = Math.min(1, maxDimension / Math.max(img.width, img.height));\n const width = Math.round(img.width * scale);\n const height = Math.round(img.height * scale);\n const canvas = document.createElement(\"canvas\");\n canvas.width = width;\n canvas.height = height;\n const ctx = canvas.getContext(\"2d\");\n if (!ctx) {\n // No canvas: hand back the original rather than nothing, and let the\n // size check decide whether it is usable.\n resolve(reader.result as string);\n return;\n }\n ctx.drawImage(img, 0, 0, width, height);\n resolve(canvas.toDataURL(\"image/png\"));\n };\n img.onerror = reject;\n img.src = reader.result as string;\n };\n reader.onerror = reject;\n reader.readAsDataURL(file);\n });\n}\n","import { forwardRef, useEffect, useRef, useState } from 'react';\nimport { Calendar, ChevronLeft, ChevronRight } from 'lucide-react';\nimport { cn } from '../utils/cn';\nimport { useAnchoredPosition } from '../utils/useAnchoredPosition';\nimport { Icon } from '../content/Icon';\n\nexport interface DatePickerProps {\n /** Current date value */\n value?: Date | null;\n /** Change handler */\n onChange?: (date: Date | null) => void;\n /** Placeholder text */\n placeholder?: string;\n /** Whether the input is disabled */\n disabled?: boolean;\n /** Whether the input is required */\n required?: boolean;\n /** Input size */\n size?: 'sm' | 'md' | 'lg' | 'full';\n /** Additional CSS classes */\n className?: string;\n /** Minimum selectable date */\n minDate?: Date;\n /** Maximum selectable date */\n maxDate?: Date;\n /** Date format for display */\n format?: 'MM/dd/yyyy' | 'dd/MM/yyyy' | 'yyyy-MM-dd';\n /**\n * Also pick a time. The display gains `HH:mm`, the panel gains a time field,\n * and choosing a day keeps the time already on the value instead of resetting\n * it to midnight. Replaces a native `datetime-local`.\n */\n withTime?: boolean;\n}\n\nconst CalendarIcon = () => <Icon icon={Calendar} size=\"md\" color=\"current\" />;\nconst ChevronLeftIcon = () => <Icon icon={ChevronLeft} size=\"md\" color=\"current\" />;\nconst ChevronRightIcon = () => <Icon icon={ChevronRight} size=\"md\" color=\"current\" />;\n\n/**\n * DatePicker component with calendar popup\n */\nexport const DatePicker = forwardRef<HTMLInputElement, DatePickerProps>(({\n value,\n onChange,\n placeholder = 'Select date',\n disabled = false,\n required = false,\n size = 'md',\n className,\n minDate,\n maxDate,\n format = 'MM/dd/yyyy',\n withTime = false,\n}, ref) => {\n const [isOpen, setIsOpen] = useState(false);\n const [currentMonth, setCurrentMonth] = useState(() => value || new Date());\n const containerRef = useRef<HTMLDivElement>(null);\n const fieldRef = useRef<HTMLDivElement>(null);\n // Fixed against the field: an absolute panel is clipped by the form panel's\n // overflow and opens below the fold when the field sits near the bottom.\n //\n // Anchored on the field, not on containerRef — the panel is a child of the\n // container, so on the first open (before the fixed position lands) it counted\n // towards the container's own height and the panel placed itself a panel's\n // length too low. Closing and reopening looked fine because the measurement\n // from the previous open was still in state.\n const panelStyle = useAnchoredPosition(isOpen, fieldRef);\n\n // Close calendar when clicking outside\n useEffect(() => {\n const handleClickOutside = (event: MouseEvent) => {\n if (containerRef.current && !containerRef.current.contains(event.target as Node)) {\n setIsOpen(false);\n }\n };\n\n if (isOpen) {\n document.addEventListener('mousedown', handleClickOutside);\n }\n\n return () => {\n document.removeEventListener('mousedown', handleClickOutside);\n };\n }, [isOpen]);\n\n // Format date for display\n const formatDate = (date: Date | null): string => {\n if (!date) return '';\n\n const day = date.getDate().toString().padStart(2, '0');\n const month = (date.getMonth() + 1).toString().padStart(2, '0');\n const year = date.getFullYear();\n\n const datePart =\n format === 'dd/MM/yyyy' ? `${day}/${month}/${year}`\n : format === 'yyyy-MM-dd' ? `${year}-${month}-${day}`\n : `${month}/${day}/${year}`;\n\n return withTime ? `${datePart} ${formatTime(date)}` : datePart;\n };\n\n /** `HH:mm`, the value shape a native time input expects. */\n const formatTime = (date: Date) =>\n `${date.getHours().toString().padStart(2, '0')}:${date.getMinutes().toString().padStart(2, '0')}`;\n\n const handleTimeChange = (next: string) => {\n const [hours, minutes] = next.split(':').map(Number);\n if (Number.isNaN(hours) || Number.isNaN(minutes)) return;\n // Time can be set before a day is picked; fall back to today.\n const base = value ? new Date(value) : new Date();\n base.setHours(hours, minutes, 0, 0);\n onChange?.(base);\n };\n\n // Get calendar days for current month\n const getCalendarDays = () => {\n const year = currentMonth.getFullYear();\n const month = currentMonth.getMonth();\n\n const firstDay = new Date(year, month, 1);\n const lastDay = new Date(year, month + 1, 0);\n const startDate = new Date(firstDay);\n startDate.setDate(startDate.getDate() - firstDay.getDay());\n\n const days = [];\n const current = new Date(startDate);\n\n for (let i = 0; i < 42; i++) {\n days.push(new Date(current));\n current.setDate(current.getDate() + 1);\n }\n\n return days;\n };\n\n const handleDateSelect = (date: Date) => {\n const isInCurrentMonth = date.getMonth() === currentMonth.getMonth();\n if (!isInCurrentMonth) return;\n\n // Check min/max constraints\n if (minDate && date < minDate) return;\n if (maxDate && date > maxDate) return;\n\n if (withTime) {\n // Carry the time across, otherwise picking a day silently resets it to 00:00.\n const picked = new Date(date);\n picked.setHours(value?.getHours() ?? 0, value?.getMinutes() ?? 0, 0, 0);\n onChange?.(picked);\n // Stay open: the time still has to be set.\n return;\n }\n\n onChange?.(date);\n setIsOpen(false);\n };\n\n const handlePrevMonth = () => {\n setCurrentMonth(new Date(currentMonth.getFullYear(), currentMonth.getMonth() - 1, 1));\n };\n\n const handleNextMonth = () => {\n setCurrentMonth(new Date(currentMonth.getFullYear(), currentMonth.getMonth() + 1, 1));\n };\n\n const handleClear = () => {\n onChange?.(null);\n setIsOpen(false);\n };\n\n const inputClasses = cn(\n 'w-full border border-border-strong rounded-tile transition-colors duration-fast',\n 'bg-surface text-text',\n 'placeholder:text-text-muted',\n 'focus-visible:outline-none focus-visible:focus-ring',\n 'disabled:cursor-not-allowed disabled:bg-surface-hover disabled:text-text-disabled',\n {\n 'h-control-sm px-3 text-sm': size === 'sm',\n 'h-control-md px-3 text-base': size === 'md',\n 'h-control-lg px-3 text-base': size === 'lg',\n 'h-control-md w-full px-3 text-base': size === 'full',\n },\n className\n );\n\n const calendarDays = getCalendarDays();\n const monthNames = [\n 'January', 'February', 'March', 'April', 'May', 'June',\n 'July', 'August', 'September', 'October', 'November', 'December'\n ];\n\n return (\n <div ref={containerRef} className=\"relative\">\n {/* Input */}\n <div ref={fieldRef} className=\"relative\">\n <input\n ref={ref}\n type=\"text\"\n value={formatDate(value ?? null)}\n placeholder={placeholder}\n disabled={disabled}\n required={required}\n readOnly\n onClick={() => !disabled && setIsOpen(!isOpen)}\n className={cn(inputClasses, 'pr-10 cursor-pointer')}\n />\n <button\n type=\"button\"\n onClick={() => !disabled && setIsOpen(!isOpen)}\n disabled={disabled}\n className=\"absolute inset-y-0 right-0 flex items-center pr-3 text-text-muted hover:text-text-muted\"\n >\n <CalendarIcon />\n </button>\n </div>\n\n {/* Calendar Popup */}\n {isOpen && (\n <div style={panelStyle} className=\"fixed z-overlay overflow-auto rounded-lg border border-border bg-surface p-4 shadow-overlay min-w-panel\">\n {/* Header */}\n <div className=\"flex items-center justify-between mb-4\">\n <button\n onClick={handlePrevMonth}\n className=\"p-1 hover:bg-surface-hover rounded\"\n >\n <ChevronLeftIcon />\n </button>\n <h3 className=\"text-sm font-medium text-text\">\n {monthNames[currentMonth.getMonth()]} {currentMonth.getFullYear()}\n </h3>\n <button\n onClick={handleNextMonth}\n className=\"p-1 hover:bg-surface-hover rounded\"\n >\n <ChevronRightIcon />\n </button>\n </div>\n\n {/* Days of week */}\n <div className=\"grid grid-cols-7 gap-1 mb-2\">\n {['Su', 'Mo', 'Tu', 'We', 'Th', 'Fr', 'Sa'].map((day) => (\n <div key={day} className=\"text-xs font-medium text-text-muted text-center py-1\">\n {day}\n </div>\n ))}\n </div>\n\n {/* Calendar grid */}\n <div className=\"grid grid-cols-7 gap-1\">\n {calendarDays.map((date, index) => {\n const isCurrentMonth = date.getMonth() === currentMonth.getMonth();\n const isSelected = value && date.toDateString() === value.toDateString();\n const isToday = date.toDateString() === new Date().toDateString();\n const isDisabled =\n !isCurrentMonth ||\n (minDate && date < minDate) ||\n (maxDate && date > maxDate);\n\n return (\n <button\n key={index}\n onClick={() => !isDisabled && handleDateSelect(date)}\n disabled={isDisabled}\n className={cn(\n 'w-8 h-8 text-sm rounded transition-colors duration-fast',\n {\n 'text-text hover:bg-surface-hover':\n isCurrentMonth && !isSelected && !isDisabled,\n 'bg-accent text-accent-fg': isSelected,\n 'bg-surface-hover text-text': isToday && !isSelected,\n 'text-text-muted cursor-not-allowed': isDisabled,\n }\n )}\n >\n {date.getDate()}\n </button>\n );\n })}\n </div>\n\n {withTime && (\n <div className=\"mt-3 flex items-center gap-2 border-t border-border pt-3\">\n <label htmlFor=\"datepicker-time\" className=\"text-sm text-text-muted\">\n Tijd\n </label>\n <input\n id=\"datepicker-time\"\n type=\"time\"\n value={value ? formatTime(value) : ''}\n onChange={(e) => handleTimeChange(e.target.value)}\n className=\"h-control-sm rounded-md border border-border bg-surface-input px-2 text-sm text-text focus-visible:outline-none focus-visible:focus-ring\"\n />\n </div>\n )}\n\n {/* Footer */}\n <div className=\"flex justify-between items-center mt-4 pt-3 border-t border-border\">\n <button\n onClick={handleClear}\n className=\"text-sm text-text-muted hover:text-text\"\n >\n Clear\n </button>\n <button\n onClick={() => setIsOpen(false)}\n className=\"text-sm text-info-fg hover:underline\"\n >\n Close\n </button>\n </div>\n </div>\n )}\n </div>\n );\n}); ","import { ChevronDownIcon } from \"lucide-react\";\nimport React, { forwardRef } from \"react\";\nimport { cn } from \"../utils/cn\";\nimport { normalizeText, text } from \"../utils/text\";\nimport { useAnchoredPosition } from \"../utils/useAnchoredPosition\";\n\nexport interface SelectOption {\n value: string;\n label: string;\n disabled?: boolean;\n}\n\nexport interface SelectProps\n extends Omit<React.HTMLAttributes<HTMLDivElement>, \"onChange\"> {\n value?: string | string[];\n onChange?: (value: string | string[]) => void;\n label?: string;\n helperText?: string;\n error?: string;\n size?: \"sm\" | \"md\" | \"lg\" | \"full\";\n fullWidth?: boolean;\n /**\n * Blocks opening the menu. The trigger is a button inside the container, so\n * this has to be forwarded explicitly — spreading it with the rest of the\n * props lands it on the wrapping div, where it does nothing.\n */\n disabled?: boolean;\n options: SelectOption[];\n placeholder?: string;\n containerClassName?: string;\n labelClassName?: string;\n searchable?: boolean;\n multiple?: boolean;\n\n /** Vrije invoer toestaan (Enter of klik op “Voeg toe…”) */\n allowCreate?: boolean;\n\n /** Optioneel: zelf bepalen hoe een nieuwe optie eruit ziet */\n onCreateOption?: (label: string) => SelectOption;\n}\n\nconst selectSizes = {\n sm: \"h-control-sm px-3 text-sm\",\n md: \"h-control-md px-3 text-sm\",\n lg: \"h-control-lg px-3 text-base\",\n full: \"h-control-md w-full px-3 text-sm\",\n};\n\n/**\n * The props below say `string`, but this component is fed straight out of form\n * data, which is `any`. See {@link text} for why that has to be coerced here.\n */\nconst norm = normalizeText;\n\nexport const Select = forwardRef<HTMLDivElement, SelectProps>(\n (\n {\n label,\n helperText,\n error,\n size = \"md\",\n fullWidth = false,\n disabled = false,\n options,\n placeholder,\n containerClassName,\n labelClassName,\n className,\n id,\n searchable,\n multiple,\n value,\n onChange,\n allowCreate,\n onCreateOption,\n ...props\n },\n ref\n ) => {\n const selectId = id || `select-${Math.random().toString(36).substr(2, 9)}`;\n const hasError = Boolean(error);\n const [isOpen, setIsOpen] = React.useState(false);\n const [searchTerm, setSearchTerm] = React.useState(\"\");\n const containerRef = React.useRef<HTMLDivElement>(null);\n // Anchored to the control itself, not the container — the container also\n // holds the label, which would push the panel down by its height.\n const triggerRef = React.useRef<HTMLButtonElement>(null);\n // Fixed, not absolute: an absolute panel is clipped by the form panel's\n // overflow and runs off-screen when the field sits near the bottom.\n const panelStyle = useAnchoredPosition(isOpen, triggerRef, { matchWidth: true });\n\n // Lokale kopie van opties, waarin we ook vrije waarden kunnen bijmengen\n const [localOptions, setLocalOptions] =\n React.useState<SelectOption[]>(options);\n\n React.useImperativeHandle(ref, () => containerRef.current!);\n\n React.useEffect(() => {\n const handleClickOutside = (event: MouseEvent) => {\n if (\n containerRef.current &&\n !containerRef.current.contains(event.target as Node)\n ) {\n setIsOpen(false);\n }\n };\n document.addEventListener(\"mousedown\", handleClickOutside);\n return () =>\n document.removeEventListener(\"mousedown\", handleClickOutside);\n }, []);\n\n // Helper: check of optie (op value/label) al bestaat\n const includesOption = React.useCallback(\n (opts: SelectOption[], needle: string) =>\n opts.some(\n (o) =>\n norm(o.value) === norm(needle) || norm(o.label) === norm(needle)\n ),\n []\n );\n\n // Voeg ontbrekende current value(s) toe aan de opties\n const ensureValuesInOptions = React.useCallback(\n (baseOptions: SelectOption[], currentValue?: unknown) => {\n const out = [...baseOptions];\n\n const addIfMissing = (v?: unknown) => {\n const val = text(v).trim();\n if (!val) return;\n if (!includesOption(out, val)) {\n out.push({ value: val, label: val });\n }\n };\n\n if (Array.isArray(currentValue)) {\n currentValue.forEach(addIfMissing);\n } else {\n addIfMissing(currentValue);\n }\n\n return out;\n },\n [includesOption]\n );\n\n // Wanneer \"options\" verandert, merge + zorg dat de huidige value(s) erin staan\n React.useEffect(() => {\n setLocalOptions((prev) => {\n // Start vanuit de nieuwe options prop\n const next = [...options];\n\n // Ook eerder lokaal aangemaakte opties behouden (zonder duplicates)\n prev.forEach((opt) => {\n if (\n !includesOption(next, opt.value) &&\n !includesOption(next, opt.label)\n ) {\n next.push(opt);\n }\n });\n\n // En zorg dat de actuele value(s) aanwezig zijn\n return ensureValuesInOptions(next, value);\n });\n }, [options, value, ensureValuesInOptions, includesOption]);\n\n /**\n * The incoming value as text, so every comparison below is string-to-string.\n * Option values are strings by contract; the value comes from form data and\n * may not be — see {@link text}.\n */\n const selected = React.useMemo(\n () => (Array.isArray(value) ? value.map(text) : value == null ? undefined : text(value)),\n [value]\n );\n\n const handleSelect = (optionValue: string) => {\n if (multiple) {\n const currentValues = Array.isArray(selected) ? selected : [];\n const newValues = currentValues.includes(optionValue)\n ? currentValues.filter((v) => v !== optionValue)\n : [...currentValues, optionValue];\n onChange?.(newValues);\n } else {\n onChange?.(optionValue);\n setIsOpen(false);\n setSearchTerm(\"\");\n }\n };\n\n const selectedOption = multiple\n ? null\n : localOptions.find((o) => o.value === selected);\n\n const selectedOptions = multiple\n ? localOptions.filter(\n (o) => Array.isArray(selected) && selected.includes(o.value)\n )\n : [];\n\n const filteredOptions =\n searchable && searchTerm\n ? localOptions.filter((option) =>\n option.label.toLowerCase().includes(searchTerm.toLowerCase())\n )\n : localOptions;\n\n const canCreate =\n Boolean(allowCreate) &&\n Boolean(searchable) &&\n Boolean(searchTerm.trim()) &&\n !includesOption(localOptions, searchTerm);\n\n const createOption = (labelToCreate: string) => {\n const clean = labelToCreate.trim();\n if (!clean) return;\n\n const newOption: SelectOption = onCreateOption?.(clean) ?? {\n value: clean,\n label: clean,\n };\n\n if (\n includesOption(localOptions, newOption.value) ||\n includesOption(localOptions, newOption.label)\n ) {\n // al aanwezig; selecteer hem gewoon\n handleSelect(newOption.value);\n setSearchTerm(\"\");\n if (!multiple) setIsOpen(false);\n return;\n }\n\n setLocalOptions((prev) => [...prev, newOption]);\n handleSelect(newOption.value);\n\n setSearchTerm(\"\");\n if (!multiple) setIsOpen(false);\n };\n\n const getDisplayValue = () => {\n if (multiple) {\n if (selectedOptions.length > 0) {\n return selectedOptions.map((o) => o.label).join(\", \");\n }\n return placeholder || \"Select options\";\n }\n return selectedOption?.label || placeholder || \"Select an option\";\n };\n\n return (\n <div\n ref={containerRef}\n className={cn(\n \"relative flex flex-col\",\n fullWidth && \"w-full\",\n containerClassName\n )}\n {...props}\n >\n {label && (\n <label\n htmlFor={selectId}\n onClick={() => setIsOpen(!isOpen)}\n className={cn(\n \"block text-xs font-semibold uppercase tracking-label mb-1.5\",\n hasError\n ? \"text-danger-fg\"\n : \"text-text-muted\",\n labelClassName\n )}\n >\n {label}\n </label>\n )}\n\n <div className=\"relative\">\n <button\n ref={triggerRef}\n type=\"button\"\n id={selectId}\n disabled={disabled}\n onClick={() => setIsOpen(!isOpen)}\n className={cn(\n \"flex w-full items-center justify-between gap-2 rounded-tile border transition-colors duration-fast text-left\",\n \"focus-visible:outline-none focus-visible:focus-ring\",\n \"disabled:cursor-not-allowed disabled:bg-surface-hover disabled:text-text-disabled\",\n \"bg-surface\",\n selectSizes[size],\n hasError\n ? \"border-danger-border text-danger-fg focus-visible:focus-ring\"\n : \"border-border-strong text-text\",\n className\n )}\n >\n <span className=\"truncate flex-1 min-w-0\">{getDisplayValue()}</span>\n <ChevronDownIcon\n size={16}\n className={cn(\n \"shrink-0 opacity-60 transition-transform duration-fast\",\n isOpen && \"rotate-180\"\n )}\n />\n </button>\n\n {isOpen && (\n <div style={panelStyle} className=\"fixed z-overlay flex flex-col overflow-hidden rounded-lg border border-border bg-surface shadow-overlay\">\n {searchable && (\n <div className=\"p-2\">\n <input\n type=\"text\"\n placeholder=\"Search...\"\n value={searchTerm}\n onChange={(e) => setSearchTerm(e.target.value)}\n onKeyDown={(e) => {\n if (e.key === \"Enter\" && canCreate) {\n e.preventDefault();\n createOption(searchTerm);\n }\n }}\n className={cn(\n \"w-full px-3 py-2 text-sm rounded-md border\",\n \"text-text border-border focus-visible:outline-none focus-visible:focus-ring\"\n )}\n />\n </div>\n )}\n\n {canCreate && (\n <div\n className={cn(\n \"cursor-pointer px-3 py-1.5 text-sm\",\n \"text-info-fg hover:bg-surface-hover\"\n )}\n onClick={() => createOption(searchTerm)}\n >\n +: “{searchTerm.trim()}”\n </div>\n )}\n\n <ul className=\"min-h-0 flex-1 overflow-auto py-1\">\n {placeholder && !multiple && (\n <li\n className=\"cursor-pointer px-3 py-1.5 text-sm text-text-muted hover:bg-surface-hover\"\n onClick={() => {\n onChange?.(\"\");\n setIsOpen(false);\n }}\n >\n {placeholder}\n </li>\n )}\n {filteredOptions.map((option) => {\n const isSelected = multiple\n ? Array.isArray(selected) && selected.includes(option.value)\n : selected === option.value;\n return (\n <li\n key={option.value}\n onClick={() =>\n !option.disabled && handleSelect(option.value)\n }\n className={cn(\n \"cursor-pointer px-3 py-1.5 text-sm\",\n \"text-text\",\n option.disabled\n ? \"opacity-50 cursor-not-allowed\"\n : \"hover:bg-surface-hover\",\n isSelected && \"bg-accent-soft text-accent font-semibold\"\n )}\n >\n <div className=\"flex items-center\">\n {multiple && (\n <input\n type=\"checkbox\"\n checked={isSelected}\n readOnly\n className=\"mr-3 h-4 w-4 rounded border-border [&:not(:checked)]:bg-surface-input text-accent \"\n />\n )}\n <span>{option.label}</span>\n </div>\n </li>\n );\n })}\n </ul>\n </div>\n )}\n </div>\n\n {(error || helperText) && (\n <p\n className={cn(\n \"mt-1 text-xs\",\n hasError ? \"text-danger-fg\" : \"text-text-muted\"\n )}\n >\n {error || helperText}\n </p>\n )}\n </div>\n );\n }\n);\n\nSelect.displayName = \"Select\";\n","import React, { forwardRef } from 'react';\nimport { cn } from '../utils/cn';\n\nexport interface TextFieldProps extends Omit<React.InputHTMLAttributes<HTMLInputElement>, 'size'> {\n /**\n * The label for the input field\n */\n label?: string;\n\n /**\n * Helper text to display below the input\n */\n helperText?: string;\n\n /**\n * Error message to display when the input is invalid\n */\n error?: string;\n\n /**\n * The size of the input field\n */\n size?: 'sm' | 'md' | 'lg' | 'full';\n\n /**\n * Whether the input should take the full width of its container\n */\n fullWidth?: boolean;\n\n /**\n * Icon to display at the start of the input\n */\n startIcon?: React.ReactNode;\n\n /**\n * Icon to display at the end of the input\n */\n endIcon?: React.ReactNode;\n\n /**\n * Whether the input is in a loading state\n */\n loading?: boolean;\n\n /**\n * Additional class name for the container\n */\n containerClassName?: string;\n\n /**\n * Additional class name for the label\n */\n labelClassName?: string;\n}\n\n/** Heights come from the control tokens — inputs, buttons and selects align. */\nconst inputSizes = {\n sm: 'h-control-sm px-3 text-sm',\n md: 'h-control-md px-3 text-base',\n lg: 'h-control-lg px-3 text-base',\n full: 'h-control-md px-3 text-base',\n};\n\n/**\n * Shared with TextArea / Select / DatePicker.\n *\n * Sentence case, not the uppercase small-caps it used to be: a form is a page\n * now, and every field label shouting in caps competes with the section titles\n * beside them. Uppercase is still the section-label treatment (`tracking-label`),\n * one level up.\n */\nexport const fieldLabelClasses = 'mb-1.5 block text-sm font-medium';\n\n/**\n * Shared field frame. A resting 1px edge in `border-strong` — a form field has\n * to read as an empty box you can type in, which the lighter `border` used for\n * structural rules does not do at this size.\n */\nexport const fieldFrameClasses =\n 'block w-full rounded-tile border bg-surface-input text-text ' +\n 'transition-colors duration-fast ease-out ' +\n 'placeholder:text-text-subtle ' +\n 'focus-visible:outline-none focus-visible:focus-ring ' +\n 'disabled:cursor-not-allowed disabled:bg-surface-hover disabled:text-text-disabled';\n\n/** Resting / error edge, shared so every control agrees on what \"invalid\" looks like. */\nexport const fieldEdgeClasses = (hasError: boolean) =>\n hasError ? 'border-danger-border bg-danger-soft' : 'border-border-strong';\n\n/**\n * TextField component with theme integration and validation states\n *\n * @example\n * ```tsx\n * <TextField label=\"E-mail\" type=\"email\" placeholder=\"naam@bedrijf.nl\" />\n * <TextField label=\"Zoeken\" startIcon={<Icon icon={Search} />} />\n * <TextField label=\"Wachtwoord\" type=\"password\" error=\"Verplicht veld\" />\n * ```\n */\nexport const TextField = forwardRef<HTMLInputElement, TextFieldProps>(\n (\n {\n label,\n helperText,\n error,\n size = 'md',\n fullWidth = false,\n startIcon,\n endIcon,\n loading = false,\n containerClassName,\n labelClassName,\n className,\n id,\n ...props\n },\n ref\n ) => {\n const reactId = React.useId();\n const inputId = id || `textfield-${reactId}`;\n const hasError = Boolean(error);\n const describedBy = error || helperText ? `${inputId}-description` : undefined;\n\n return (\n <div className={cn('flex flex-col', fullWidth && 'w-full', containerClassName)}>\n {label && (\n <label\n htmlFor={inputId}\n className={cn(\n fieldLabelClasses,\n hasError ? 'text-danger-fg' : 'text-text-muted',\n labelClassName\n )}\n >\n {label}\n </label>\n )}\n\n <div className=\"relative\">\n {startIcon && (\n <span className=\"pointer-events-none absolute inset-y-0 left-0 flex items-center pl-3 text-text-muted\">\n {startIcon}\n </span>\n )}\n\n <input\n ref={ref}\n id={inputId}\n aria-invalid={hasError || undefined}\n aria-describedby={describedBy}\n className={cn(\n fieldFrameClasses,\n\n inputSizes[size],\n\n startIcon && 'pl-9',\n (endIcon || loading) && 'pr-9',\n\n fieldEdgeClasses(hasError),\n\n className\n )}\n {...props}\n />\n\n {(endIcon || loading) && (\n <span className=\"absolute inset-y-0 right-0 flex items-center pr-3 text-text-muted\">\n {loading ? (\n <span\n aria-hidden\n className=\"size-icon-md animate-spin rounded-full border-2 border-border border-t-transparent\"\n />\n ) : (\n endIcon\n )}\n </span>\n )}\n </div>\n\n {(error || helperText) && (\n <p\n id={describedBy}\n className={cn('mt-1 text-xs', hasError ? 'text-danger-fg' : 'text-text-subtle')}\n >\n {error || helperText}\n </p>\n )}\n </div>\n );\n }\n);\n\nTextField.displayName = 'TextField';\n","import { VirtualMount } from \"@opencxh/domain\";\nimport { useEffect, useState } from \"react\";\nimport { Select } from \"./Select\";\nimport { TextField } from \"./TextField\";\n\nexport interface FolderDestination {\n /** Storage folder (mount) id. */\n folderId?: string;\n /** Optional sub-path template, e.g. \"{yyyy}/{mm}/{dd}\". */\n pathTemplate?: string;\n}\n\nexport interface FolderSelectProps {\n value?: FolderDestination;\n onChange?: (value: FolderDestination) => void;\n /** Loads the selectable storage folders (the shell wires this to storage.mount). */\n onListFolders?: () => Promise<{ data: VirtualMount[] }> | undefined;\n disabled?: boolean;\n size?: \"sm\" | \"md\" | \"lg\" | \"full\";\n placeholder?: string;\n templatePlaceholder?: string;\n /** Show the sub-path template input (default true). */\n showTemplate?: boolean;\n}\n\n/**\n * Destination picker for a storage folder (+ optional sub-path template).\n * Unlike StorageInput (which picks/uploads a file), this selects *where* things\n * should be written. Used by the `type: \"folder\"` form field.\n */\nexport function FolderSelect({\n value,\n onChange,\n onListFolders,\n disabled,\n size = \"md\",\n placeholder,\n templatePlaceholder,\n showTemplate = true,\n}: FolderSelectProps) {\n const [folders, setFolders] = useState<VirtualMount[]>([]);\n\n useEffect(() => {\n let active = true;\n Promise.resolve(onListFolders?.())\n .then((res) => {\n if (active && res) setFolders(res.data ?? []);\n })\n .catch(() => {\n /* folder list unavailable */\n });\n return () => {\n active = false;\n };\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, []);\n\n const v = value ?? {};\n\n return (\n <div className=\"flex flex-col gap-2\">\n <Select\n size={size}\n fullWidth\n value={v.folderId ?? \"\"}\n options={folders.map((f) => ({ value: f.id, label: f.name }))}\n placeholder={placeholder ?? \"Select a folder\"}\n onChange={(val) => onChange?.({ ...v, folderId: val as string })}\n />\n {showTemplate && (\n <TextField\n size={size}\n disabled={disabled ?? false}\n value={v.pathTemplate ?? \"\"}\n placeholder={templatePlaceholder ?? \"Sub-path e.g. {yyyy}/{mm}/{dd} (optional)\"}\n onChange={(e) => onChange?.({ ...v, pathTemplate: e.target.value })}\n />\n )}\n </div>\n );\n}\n","import React, { forwardRef, useEffect, useMemo, useRef, useState } from \"react\";\nimport { ChevronDown, Loader2, Search } from \"lucide-react\";\n\nconst cn = (...classes: string[]) => classes.filter(Boolean).join(\" \");\n\nconst SearchIcon = (props: React.SVGProps<SVGSVGElement>) => (\n <Search {...props} strokeWidth={1.5} aria-hidden />\n);\n\nconst ChevronDownIcon = (props: React.SVGProps<SVGSVGElement>) => (\n <ChevronDown {...props} strokeWidth={1.5} aria-hidden />\n);\n\nconst inputSizes = {\n sm: \"h-control-sm px-3 text-sm\",\n md: \"h-control-md px-3 text-base\",\n lg: \"h-control-lg px-3 text-base\",\n full: \"h-control-md w-full px-3 text-base\",\n};\n\nconst iconSizes = {\n sm: \"h-4 w-4\",\n md: \"h-5 w-5\",\n lg: \"h-6 w-6\",\n full: \"h-6 w-6\",\n};\n\nexport interface SearchableTextFieldOption {\n value: string;\n label: string;\n}\n\nexport interface SearchableTextFieldProps\n extends Omit<\n React.InputHTMLAttributes<HTMLInputElement>,\n \"size\" | \"onSelect\"\n > {\n label?: string;\n helperText?: string;\n error?: string;\n size?: \"sm\" | \"md\" | \"lg\" | \"full\";\n fullWidth?: boolean;\n startIcon?: React.ReactNode;\n loading?: boolean;\n containerClassName?: string;\n labelClassName?: string;\n\n options: SearchableTextFieldOption[];\n onRemoteSearch?: (searchTerm: string) => Promise<void>;\n\n onSelect?: (value: string) => void;\n debounceTime?: number;\n /**\n * Selector-modus: toon bij openen (focus/chevron) álle opties, ook wanneer de\n * huidige waarde een reeds geselecteerde optie is. Pas zodra de gebruiker zelf\n * typt wordt er gefilterd. Handig wanneer het veld eerder een keuzelijst is dan\n * een vrije zoekopdracht (bv. een afzender-selector).\n */\n showAllOnOpen?: boolean;\n}\n\nexport const SearchableTextField = forwardRef<\n HTMLInputElement,\n SearchableTextFieldProps\n>(\n (\n {\n label,\n helperText,\n error,\n size = \"md\",\n fullWidth = false,\n startIcon = <SearchIcon />,\n loading: externalLoading = false,\n containerClassName,\n labelClassName,\n className,\n id,\n options,\n onRemoteSearch,\n onSelect,\n debounceTime = 500,\n showAllOnOpen = false,\n value: propValue,\n onChange,\n ...props\n },\n ref\n ) => {\n const inputId =\n id || `searchfield-${Math.random().toString(36).substr(2, 9)}`;\n const hasError = Boolean(error);\n const containerRef = useRef(null);\n const inputRef = useRef(null);\n\n const [inputValue, setInputValue] = useState(propValue || \"\");\n const [isOpen, setIsOpen] = useState(false);\n const [isSearchingRemote, setIsSearchingRemote] = useState(false);\n // In selector-modus: is er sinds het openen daadwerkelijk getypt? Zo niet,\n // dan tonen we de volledige lijst i.p.v. te filteren op de gekozen waarde.\n const [typedSinceOpen, setTypedSinceOpen] = useState(false);\n\n useEffect(() => {\n if (propValue !== undefined) {\n setInputValue(propValue);\n }\n }, [propValue]);\n\n const filteredOptions = useMemo(() => {\n if (showAllOnOpen && !typedSinceOpen) return options;\n if (!inputValue) return options;\n const lowerCaseInput = String(inputValue).toLowerCase();\n return options.filter((option) =>\n String(option.label).toLowerCase().includes(lowerCaseInput)\n );\n }, [inputValue, options, showAllOnOpen, typedSinceOpen]);\n\n useEffect(() => {\n if (!onRemoteSearch || !inputValue) {\n setIsSearchingRemote(false);\n return;\n }\n\n const handler = setTimeout(async () => {\n setIsSearchingRemote(true);\n try {\n await onRemoteSearch(String(inputValue));\n } catch (e) {\n console.error(\"Remote search failed:\", e);\n } finally {\n setIsSearchingRemote(false);\n }\n }, debounceTime);\n\n return () => {\n clearTimeout(handler);\n setIsSearchingRemote(false);\n };\n }, [inputValue, debounceTime, onRemoteSearch]);\n\n useEffect(() => {\n const handleClickOutside = (event: MouseEvent) => {\n if (\n containerRef.current &&\n !(containerRef.current as HTMLElement).contains(event.target as Node)\n ) {\n setIsOpen(false);\n }\n };\n document.addEventListener(\"mousedown\", handleClickOutside);\n return () =>\n document.removeEventListener(\"mousedown\", handleClickOutside);\n }, []);\n\n const handleChange = (e: React.ChangeEvent<HTMLInputElement>) => {\n const newValue = e.target.value;\n setInputValue(newValue);\n setIsOpen(true);\n setTypedSinceOpen(true);\n if (onChange) {\n onChange(e);\n }\n };\n\n const handleSelect = (option: SearchableTextFieldOption) => {\n setInputValue(option.label);\n setIsOpen(false);\n setTypedSinceOpen(false);\n if (onSelect) {\n onSelect(option.value);\n }\n };\n\n const handleFocus = () => {\n // Open dropdown alleen als er opties zijn of remote search beschikbaar is\n if (options.length > 0 || onRemoteSearch) {\n setIsOpen(true);\n setTypedSinceOpen(false);\n }\n };\n\n const loading = externalLoading || isSearchingRemote;\n\n const showDropdown = isOpen && (filteredOptions.length > 0 || loading);\n\n const resolvedRef = useMemo(() => ref || inputRef, [ref]);\n\n return (\n <div\n className={cn(\n \"flex flex-col\",\n fullWidth ? \"w-full\" : \"\",\n containerClassName || \"\",\n \"relative\"\n )}\n ref={containerRef}\n >\n {label && (\n <label\n htmlFor={inputId}\n className={cn(\n \"block text-sm font-medium mb-1\",\n hasError ? \"text-danger-fg\" : \"text-text\",\n labelClassName || \"\"\n )}\n >\n {label}\n </label>\n )}\n\n <div className=\"relative\">\n {startIcon && (\n <div className=\"absolute left-0 pl-3 flex items-center pointer-events-none h-full\">\n <span className={cn(\"text-text-muted\", iconSizes[size])}>\n {startIcon}\n </span>\n </div>\n )}\n\n <input\n ref={resolvedRef}\n id={inputId}\n value={inputValue}\n onChange={handleChange}\n onFocus={handleFocus}\n className={cn(\n // Base styles\n \"block w-full rounded-tile border bg-surface-input transition-colors duration-fast ease-out\",\n \"placeholder:text-text-subtle focus-visible:outline-none focus-visible:focus-ring\",\n \"disabled:cursor-not-allowed disabled:bg-surface-hover disabled:text-text-disabled\",\n\n // Size styles\n inputSizes[size],\n\n // Icon padding\n startIcon ? \"pl-10\" : \"\",\n \"pr-10\", // Altijd padding rechts voor de dropdown/loading icon\n\n // State styles\n hasError\n ? \"border-danger-border text-danger-fg focus-visible:focus-ring\"\n : \"border-border-strong text-text\",\n\n className || \"\"\n )}\n {...props}\n />\n\n {/* END ICON (Laden/Dropdown) */}\n <div className=\"absolute inset-y-0 right-0 pr-3 flex items-center\">\n {loading || externalLoading ? (\n // Loading Spinner\n <Loader2\n className={cn(\"animate-spin text-info-fg\", iconSizes[size])}\n aria-hidden\n />\n ) : (\n // Dropdown Chevron\n <ChevronDownIcon\n className={cn(\n \"text-text-muted cursor-pointer transition-transform\",\n iconSizes[size],\n isOpen ? \"rotate-180\" : \"rotate-0\"\n )}\n onClick={() => {\n setIsOpen((prev) => {\n if (!prev) setTypedSinceOpen(false);\n return !prev;\n });\n }}\n />\n )}\n </div>\n </div>\n\n {/* DROPDOWN LIJST */}\n {showDropdown && (\n <ul\n className=\"absolute z-10 mt-1 w-full bg-surface border border-border rounded-lg shadow-lg max-h-60 overflow-auto top-full\"\n role=\"listbox\"\n >\n {filteredOptions.length > 0 ? (\n filteredOptions.map((option: SearchableTextFieldOption) => (\n <li\n key={option.value}\n className=\"px-4 py-2 cursor-pointer text-text hover:bg-accent-soft hover:text-accent transition-colors\"\n onClick={() => handleSelect(option)}\n role=\"option\"\n aria-selected={inputValue === option.label}\n >\n {option.label}\n </li>\n ))\n ) : (\n <li className=\"px-4 py-2 text-text-muted\">\n {loading || externalLoading\n ? \"Zoeken op afstand...\"\n : \"Geen resultaten gevonden.\"}\n </li>\n )}\n </ul>\n )}\n\n {/* HELPER/ERROR TEKST */}\n {(error || helperText) && (\n <p\n className={cn(\n \"mt-1 text-xs\",\n hasError ? \"text-danger-fg\" : \"text-text-muted\"\n )}\n >\n {error || helperText}\n </p>\n )}\n\n {/* Eenvoudig voorbeeld van de huidige status voor demo */}\n {onRemoteSearch && (\n <p className=\"mt-2 text-xs text-success-fg\">\n Huidige zoekterm (niet-gedebounced): {String(inputValue)}\n </p>\n )}\n </div>\n );\n }\n);\n\nSearchableTextField.displayName = \"SearchableTextField\";\n","import { Search, X } from \"lucide-react\";\nimport React, { forwardRef } from \"react\";\nimport { Icon } from \"../content/Icon\";\nimport { cn } from \"../utils/cn\";\n\nexport interface SearchFieldProps\n extends Omit<React.InputHTMLAttributes<HTMLInputElement>, \"size\" | \"value\" | \"onChange\" | \"type\"> {\n /** Current query. Controlled — this field has no internal state. */\n value: string;\n /** Called with the new query text (not the event). */\n onValueChange: (value: string) => void;\n /**\n * Keyboard hint shown at the trailing edge while the field is empty —\n * `⌘K`, `⌘F`. Replaced by the clear button once there is a query.\n */\n hint?: string;\n /** `md` is the default control height; `sm` for a dense bar. */\n size?: \"sm\" | \"md\";\n /** Accessible name for the clear button. */\n clearLabel?: string;\n /** Classes for the plate around the input. */\n containerClassName?: string;\n}\n\n/**\n * The sunk, frameless search plate: a magnifier, the query, and either a\n * keyboard hint or a clear button. It is deliberately *not* a `TextField` —\n * a bordered box would read as one more empty input in a toolbar that already\n * has filter chips and buttons, where this is the thing you type into.\n *\n * Three places had grown their own copy of it (the nav search, the settings\n * search, the table toolbar); they share this one now.\n *\n * @example\n * ```tsx\n * <SearchField value={query} onValueChange={setQuery} placeholder=\"Zoeken\" hint=\"⌘K\" />\n * ```\n */\nexport const SearchField = forwardRef<HTMLInputElement, SearchFieldProps>(\n (\n {\n value,\n onValueChange,\n hint,\n size = \"md\",\n clearLabel = \"Clear search\",\n containerClassName,\n className,\n disabled,\n ...props\n },\n ref,\n ) => (\n <div\n className={cn(\n // No focus ring: the plate is a container, not the control, and a ring\n // around a frameless search box reads as the border it deliberately\n // does not have.\n \"flex items-center gap-2 rounded-md bg-surface-sunk px-2.5 text-text-muted\",\n \"transition-colors duration-fast ease-out\",\n size === \"sm\" ? \"h-control-sm\" : \"h-control-md\",\n disabled && \"opacity-60\",\n containerClassName,\n )}\n >\n <Icon icon={Search} size=\"md\" color=\"current\" className=\"shrink-0\" />\n\n <input\n ref={ref}\n type=\"search\"\n value={value}\n disabled={disabled}\n onChange={(event) => onValueChange(event.target.value)}\n className={cn(\n // The forms base layer hands every input a white fill, a 1px border\n // and a blue focus ring; a field that is only a caret inside a plate\n // has to switch all three off explicitly. Padding too — the base rule\n // sets 8/12px, which would push the text off the plate.\n \"min-w-0 flex-1 border-0 bg-transparent p-0 text-sm text-text shadow-none\",\n \"placeholder:text-text-subtle\",\n \"focus:border-0 focus:shadow-none focus:outline-none focus:ring-0\",\n // The UA search decorations (the WebKit cancel button) would sit\n // beside our own clear button.\n \"[&::-webkit-search-cancel-button]:appearance-none\",\n className,\n )}\n {...props}\n />\n\n {value ? (\n <button\n type=\"button\"\n aria-label={clearLabel}\n onClick={() => onValueChange(\"\")}\n className=\"grid size-4 shrink-0 cursor-pointer place-items-center rounded-xs text-text-subtle transition-colors duration-fast ease-out hover:text-text focus-visible:outline-none focus-visible:focus-ring\"\n >\n <Icon icon={X} size=\"sm\" color=\"current\" />\n </button>\n ) : (\n hint && <span className=\"shrink-0 text-xs text-text-subtle\">{hint}</span>\n )}\n </div>\n ),\n);\n\nSearchField.displayName = \"SearchField\";\n","import React, { forwardRef } from \"react\";\nimport { cn } from \"../utils/cn\";\n\nexport interface SwitchProps\n extends Omit<React.InputHTMLAttributes<HTMLInputElement>, \"type\" | \"size\" | \"checked\" | \"onChange\"> {\n /**\n * Current state. Deliberately required and never held internally: several\n * call sites drive this from an optimistic update that rolls back on a failed\n * request, and internal state would silently swallow the rollback.\n */\n checked: boolean;\n onChange: (checked: boolean) => void;\n /** Text beside the switch. Omit it and pass `aria-label` instead. */\n label?: React.ReactNode;\n disabled?: boolean;\n}\n\n/**\n * On/off switch for a setting that applies immediately.\n *\n * Use `Checkbox` instead when the value is part of a form the user submits —\n * a switch says \"this is now on\", a checkbox says \"include this when I save\".\n *\n * @example\n * ```tsx\n * <Switch checked={syncEnabled} onChange={setSyncEnabled} label=\"Agenda synchroniseren\" />\n * ```\n */\nexport const Switch = forwardRef<HTMLInputElement, SwitchProps>(\n ({ checked, onChange, label, disabled = false, className, ...props }, ref) => {\n const track = (\n <span\n aria-hidden\n className={cn(\n \"relative inline-flex size-switch-track shrink-0 items-center rounded-full\",\n \"transition-colors duration-fast ease-out\",\n checked ? \"bg-accent\" : \"bg-surface-hover\",\n disabled && \"opacity-50\"\n )}\n >\n <span\n className={cn(\n \"absolute left-0.5 size-switch-knob rounded-full bg-surface shadow-overlay\",\n \"transition-transform duration-fast ease-out\",\n checked && \"translate-switch\"\n )}\n />\n </span>\n );\n\n return (\n <label\n className={cn(\n \"inline-flex items-center gap-2\",\n disabled ? \"cursor-not-allowed\" : \"cursor-pointer\",\n className\n )}\n >\n <input\n ref={ref}\n type=\"checkbox\"\n role=\"switch\"\n checked={checked}\n disabled={disabled}\n onChange={(event) => onChange(event.target.checked)}\n className=\"peer sr-only\"\n {...props}\n />\n {/* The ring lives on the track, since the input itself is visually hidden. */}\n <span className=\"inline-flex rounded-full peer-focus-visible:focus-ring\">{track}</span>\n {label && <span className=\"text-sm text-text\">{label}</span>}\n </label>\n );\n }\n);\n\nSwitch.displayName = \"Switch\";\n","import { Check } from \"lucide-react\";\nimport React, { useEffect, useRef, useState } from \"react\";\nimport { cn } from \"../utils/cn\";\nimport { useAnchoredPosition } from \"../utils/useAnchoredPosition\";\n\nexport interface DropdownOption {\n /** Option value */\n value: string;\n /** Option label */\n label: string;\n /** Option icon */\n icon?: React.ReactNode;\n /** Whether option is disabled */\n disabled?: boolean;\n /** Whether option is a divider */\n divider?: boolean;\n /** Optional description for the option */\n description?: string;\n /** Nested sub-options */\n children?: DropdownOption[];\n}\n\nexport interface DropdownProps {\n /** Dropdown trigger element */\n trigger: React.ReactNode;\n /** Dropdown options */\n options: DropdownOption[];\n /** Selected value */\n value?: string | Record<string, string | string[]>;\n /** Change handler */\n onSelect?: (value: string, parentValue?: string) => void;\n /** Dropdown placement */\n placement?: \"bottom-start\" | \"bottom-end\" | \"top-start\" | \"top-end\";\n /** Whether dropdown is disabled */\n disabled?: boolean;\n /** Additional CSS classes */\n className?: string;\n /** Show check mark for selected option */\n showCheck?: boolean;\n /** Header text for the dropdown */\n header?: string | React.ReactNode;\n}\n\n/**\n * Dropdown component for menus and select-like interfaces\n */\nexport const Dropdown: React.FC<DropdownProps> = ({\n trigger,\n options,\n value,\n onSelect,\n placement = \"bottom-start\",\n disabled = false,\n className,\n showCheck = true,\n header,\n}) => {\n const [isOpen, setIsOpen] = useState(false);\n const [hoveredOption, setHoveredOption] = useState<\n string | Record<string, string | string[]> | null\n >(null);\n const [submenuPosition, setSubmenuPosition] = useState({ top: 0, left: 0 });\n // Menu is position:fixed (computed from the trigger) so it escapes any\n // overflow-hidden / rounded-card ancestor instead of being clipped.\n const dropdownRef = useRef<HTMLDivElement>(null);\n const triggerRef = useRef<HTMLButtonElement>(null);\n const submenuRef = useRef<HTMLDivElement>(null);\n const menuRef = useRef<HTMLDivElement>(null);\n const menuPos = useAnchoredPosition(isOpen, triggerRef, { placement });\n const hideTimeoutRef = useRef<NodeJS.Timeout | null>(null);\n\n /** Enabled option buttons in the open menu, in DOM order. */\n const menuItems = () =>\n Array.from(\n menuRef.current?.querySelectorAll<HTMLButtonElement>(\"button[data-option-value]:not(:disabled)\") ?? []\n );\n\n // Move focus into the menu when it opens, so the keyboard lands somewhere\n // useful instead of on the page behind it.\n useEffect(() => {\n if (isOpen) menuItems()[0]?.focus();\n }, [isOpen]);\n\n /** Roving focus: ↓/↑ wrap through the options, Home/End jump to the ends. */\n const handleMenuKeyDown = (event: React.KeyboardEvent<HTMLDivElement>) => {\n const keys = [\"ArrowDown\", \"ArrowUp\", \"Home\", \"End\"];\n if (!keys.includes(event.key)) return;\n\n const items = menuItems();\n if (items.length === 0) return;\n event.preventDefault();\n\n const current = items.indexOf(document.activeElement as HTMLButtonElement);\n const next =\n event.key === \"Home\" ? 0\n : event.key === \"End\" ? items.length - 1\n : event.key === \"ArrowDown\" ? (current + 1) % items.length\n : (current - 1 + items.length) % items.length;\n\n items[next]?.focus();\n };\n\n // Close dropdown when clicking outside\n useEffect(() => {\n const handleClickOutside = (event: MouseEvent) => {\n if (\n dropdownRef.current &&\n (!dropdownRef.current.contains(event.target as Node) ||\n (submenuRef.current &&\n !submenuRef.current.contains(event.target as Node)))\n ) {\n setIsOpen(false);\n setHoveredOption(null);\n if (hideTimeoutRef.current) {\n clearTimeout(hideTimeoutRef.current);\n hideTimeoutRef.current = null;\n }\n }\n };\n\n if (isOpen) {\n document.addEventListener(\"mousedown\", handleClickOutside);\n }\n\n return () => {\n document.removeEventListener(\"mousedown\", handleClickOutside);\n };\n }, [isOpen]);\n\n // Close dropdown on escape key\n useEffect(() => {\n const handleEscape = (event: KeyboardEvent) => {\n if (event.key === \"Escape\") {\n setIsOpen(false);\n setHoveredOption(null);\n // Hand focus back to the trigger; otherwise it falls to <body> and the\n // keyboard user loses their place.\n triggerRef.current?.focus();\n if (hideTimeoutRef.current) {\n clearTimeout(hideTimeoutRef.current);\n hideTimeoutRef.current = null;\n }\n }\n };\n\n if (isOpen) {\n document.addEventListener(\"keydown\", handleEscape);\n }\n\n return () => {\n document.removeEventListener(\"keydown\", handleEscape);\n };\n }, [isOpen]);\n\n // Calculate submenu position when hovering over an option with children\n useEffect(() => {\n if (hoveredOption && dropdownRef.current) {\n const hoveredElement = dropdownRef.current.querySelector(\n `[data-option-value=\"${hoveredOption}\"]`\n );\n if (hoveredElement) {\n const rect = hoveredElement.getBoundingClientRect();\n setSubmenuPosition({\n top: rect.top,\n left: rect.right + 8,\n });\n }\n }\n }, [hoveredOption]);\n\n // Cleanup timeout on unmount\n useEffect(() => {\n return () => {\n if (hideTimeoutRef.current) {\n clearTimeout(hideTimeoutRef.current);\n }\n };\n }, []);\n\n const handleTriggerClick = (event: React.MouseEvent<HTMLButtonElement>) => {\n event.stopPropagation();\n if (disabled) return;\n setIsOpen(!isOpen);\n setHoveredOption(null);\n if (hideTimeoutRef.current) {\n clearTimeout(hideTimeoutRef.current);\n hideTimeoutRef.current = null;\n }\n };\n\n const handleOptionClick = (\n event: React.MouseEvent<HTMLButtonElement>,\n option: DropdownOption,\n parentValue?: string\n ) => {\n event.stopPropagation();\n if (!option.disabled && !option.divider) {\n // Only close dropdown if option has no children\n if (!option.children || option.children.length === 0) {\n onSelect?.(option.value, parentValue);\n setIsOpen(false);\n setHoveredOption(null);\n }\n }\n };\n\n const handleOptionHover = (option: DropdownOption) => {\n // Clear any existing timeout\n if (hideTimeoutRef.current) {\n clearTimeout(hideTimeoutRef.current);\n hideTimeoutRef.current = null;\n }\n\n if (option.children && option.children.length > 0) {\n setHoveredOption(option.value);\n } else {\n setHoveredOption(null);\n }\n };\n\n const handleOptionLeave = (option: DropdownOption) => {\n // Only hide if the option has children, and add a small delay\n if (option.children && option.children.length > 0) {\n hideTimeoutRef.current = setTimeout(() => {\n setHoveredOption(null);\n }, 150); // 150ms delay\n } else {\n setHoveredOption(null);\n }\n };\n\n const handleSubmenuOptionClick = (\n event: React.MouseEvent<HTMLButtonElement>,\n option: DropdownOption,\n parentValue?: string\n ) => {\n event.stopPropagation();\n if (!option.disabled && !option.divider) {\n onSelect?.(option.value, parentValue);\n setIsOpen(false);\n setHoveredOption(null);\n }\n };\n\n const dropdownClasses = cn(\n \"fixed z-overlay min-w-menu bg-surface rounded-lg shadow-overlay border border-border\",\n \"max-h-60 overflow-auto\"\n );\n\n const submenuClasses = cn(\n \"fixed z-overlay min-w-menu bg-surface rounded-lg shadow-overlay border border-border\",\n \"max-h-60 overflow-auto\"\n );\n\n return (\n <div\n ref={dropdownRef}\n className={cn(\n \"relative flex flex-row items-center justify-center rounded-lg hover:bg-surface-hover\",\n className\n )}\n >\n {/* Trigger */}\n <button\n ref={triggerRef}\n onClick={handleTriggerClick}\n disabled={disabled}\n aria-haspopup=\"menu\"\n aria-expanded={isOpen}\n className={cn(\"inline-flex items-center justify-center\", {\n \"opacity-50 cursor-not-allowed\": disabled,\n })}\n >\n {trigger}\n </button>\n\n {/* Dropdown menu */}\n {isOpen && (\n <div ref={menuRef} className={dropdownClasses} style={menuPos} onKeyDown={handleMenuKeyDown}>\n <div className=\"p-2\" role=\"menu\">\n {/* Header */}\n {header && (\n typeof header === \"string\" ? (\n <div className=\"text-xs font-medium text-text-muted uppercase tracking-label px-3 py-2\">\n {header}\n </div>\n ) : (\n header\n )\n )}\n\n {options.map((option, index) => {\n if (option.divider) {\n return (\n <div\n key={`divider-${index}`}\n className=\"border-t border-border my-2\"\n />\n );\n }\n\n const hasChildren = option.children && option.children.length > 0;\n const isHovered = hoveredOption === option.value;\n\n return (\n <div key={option.value} className=\"relative group\">\n <button\n data-option-value={option.value}\n role=\"menuitem\"\n aria-haspopup={hasChildren ? \"menu\" : undefined}\n onClick={(event) => handleOptionClick(event, option)}\n onMouseEnter={() => handleOptionHover(option)}\n onMouseLeave={() => handleOptionLeave(option)}\n disabled={option.disabled}\n className={cn(\n \"flex w-full items-center justify-between rounded-md px-3 py-1.5 text-sm text-text transition-colors duration-fast ease-out hover:bg-surface-hover focus-visible:outline-none focus-visible:focus-ring\",\n {\n \"opacity-50 cursor-not-allowed\": option.disabled,\n \"bg-surface-hover\":\n isHovered && hasChildren,\n }\n )}\n >\n <div className=\"flex items-center space-x-2 min-w-0\">\n {option.icon && (\n <span className=\"flex-shrink-0\">{option.icon}</span>\n )}\n <div className=\"flex flex-col items-start min-w-0\">\n <span className=\"font-base truncate\">\n {option.label}\n </span>\n {option.description && (\n <span className=\"text-xs text-text-muted\">\n {option.description}\n </span>\n )}\n </div>\n </div>\n\n <div className=\"flex items-center space-x-2\">\n {showCheck && value === option.value && (\n <Check className=\"size-icon-md shrink-0 text-success-fg\" aria-hidden />\n )}\n {hasChildren && (\n <span className=\"text-text-muted text-xs\">\n ▶\n </span>\n )}\n </div>\n </button>\n\n {/* Nested submenu */}\n {hasChildren && isHovered && (\n <div\n ref={submenuRef}\n className={submenuClasses}\n style={{\n top: `${submenuPosition.top}px`,\n left: `${submenuPosition.left}px`,\n }}\n onMouseEnter={() => {\n // Clear any pending hide timeout\n if (hideTimeoutRef.current) {\n clearTimeout(hideTimeoutRef.current);\n hideTimeoutRef.current = null;\n }\n setHoveredOption(option.value);\n }}\n onMouseLeave={() => {\n // Add a small delay before hiding\n hideTimeoutRef.current = setTimeout(() => {\n setHoveredOption(null);\n }, 150);\n }}\n >\n <div className=\"p-2\">\n {option.children!.map((childOption, childIndex) => {\n if (childOption.divider) {\n return (\n <div\n key={`divider-${childIndex}`}\n className=\"border-t border-border my-2\"\n />\n );\n }\n\n const isSelected =\n (typeof value === \"object\" &&\n value[option.value] &&\n value[option.value].includes(\n childOption.value\n )) ||\n value === childOption.value;\n\n return (\n <button\n key={childOption.value}\n onClick={(event) =>\n handleSubmenuOptionClick(\n event,\n childOption,\n option.value\n )\n }\n disabled={childOption.disabled}\n className={cn(\n \"flex w-full items-center justify-between rounded-md px-3 py-1.5 text-sm text-text transition-colors duration-fast ease-out hover:bg-surface-hover\",\n {\n \"opacity-50 cursor-not-allowed\":\n childOption.disabled,\n }\n )}\n >\n <div className=\"flex items-center space-x-2 min-w-0\">\n {childOption.icon && (\n <span className=\"flex-shrink-0\">\n {childOption.icon}\n </span>\n )}\n <div className=\"flex flex-col items-start min-w-0\">\n <span className=\"font-base truncate\">\n {childOption.label}\n </span>\n {childOption.description && (\n <span className=\"text-xs text-text-muted\">\n {childOption.description}\n </span>\n )}\n </div>\n </div>\n\n {showCheck && isSelected && (\n <Check className=\"size-icon-md shrink-0 text-success-fg\" aria-hidden />\n )}\n </button>\n );\n })}\n </div>\n </div>\n )}\n </div>\n );\n })}\n\n {/* Footer with count */}\n {(() => {\n const totalOptions = options.reduce((count, option) => {\n if (option.divider) return count;\n const childCount = option.children\n ? option.children.filter((child) => !child.divider).length\n : 0;\n return count + 1 + childCount;\n }, 0);\n\n return (\n totalOptions > 1 && (\n <div className=\"border-t border-border mt-2 pt-2\">\n <div className=\"text-xs text-text-muted px-3 py-1\">\n {totalOptions} options available\n </div>\n </div>\n )\n );\n })()}\n </div>\n </div>\n )}\n </div>\n );\n};\n","import { ChevronLeft } from \"lucide-react\";\nimport React from \"react\";\nimport { Button, type ButtonProps } from \"../action/Button\";\nimport { SplitButton } from \"../action/SplitButton\";\nimport { cn } from \"../utils/cn\";\nimport { Icon } from \"./Icon\";\nimport type { PageHeaderAction } from \"./PageHeader\";\n\nexport interface PageToolbarActionsProps {\n actions: PageHeaderAction[];\n /**\n * Variant for actions that do not name one. `secondary` (a sunk plate) suits\n * a detail page's Cancel/Save pair; a list toolbar passes `ghost`, because\n * there the plate would collide with the sunk search field beside it.\n */\n defaultVariant?: ButtonProps[\"variant\"];\n className?: string;\n}\n\n/**\n * The action cluster shared by `PageToolbar` and the table toolbar, so a\n * \"New …\" button looks the same wherever a view decides to put it.\n */\nexport const PageToolbarActions: React.FC<PageToolbarActionsProps> = ({\n actions,\n defaultVariant = \"secondary\",\n className,\n}) => {\n if (actions.length === 0) return null;\n\n return (\n <div className={cn(\"flex flex-wrap items-center gap-2\", className)}>\n {actions.map((action) =>\n action.render ? (\n <React.Fragment key={action.id}>{action.render()}</React.Fragment>\n ) : action.splitOptions && action.splitOptions.length > 0 ? (\n <SplitButton\n key={action.id}\n label={action.label}\n onClick={action.onClick}\n icon={action.icon}\n variant={action.variant === \"primary\" ? \"primary\" : \"secondary\"}\n options={action.splitOptions}\n disabled={action.disabled}\n />\n ) : (\n <Button\n key={action.id}\n variant={action.variant ?? defaultVariant}\n onClick={(e) => {\n e.stopPropagation();\n (e.target as HTMLButtonElement).blur();\n action.onClick();\n }}\n disabled={action.disabled}\n leftIcon={action.icon}\n >\n {action.label}\n </Button>\n )\n )}\n </div>\n );\n};\n\nexport interface PageToolbarProps {\n /** Right-aligned action buttons */\n actions?: PageHeaderAction[];\n /** Renders a ghost back button on the left */\n onBack?: () => void;\n /** Back button label (visually hidden on small screens) */\n backLabel?: string;\n /** Additional CSS classes */\n className?: string;\n /** Padding on the left and right of the toolbar */\n padding?: \"none\" | \"sm\" | \"md\" | \"lg\";\n /** Optional extra content placed between back button and actions */\n children?: React.ReactNode;\n}\n\nconst paddingClasses = {\n none: \"p-0\",\n sm: \"p-2\",\n md: \"px-5 py-4\",\n lg: \"p-6\",\n};\n\n/**\n * Thin action-bar for views that already have a host header (e.g. a settings\n * page or a detail view). Renders an optional back button on the left and\n * action buttons on the right. Use `PageHeader` when the view needs its own\n * title/breadcrumbs — and for a list, put the actions on the `Table` toolbar\n * instead, next to the search and filters they apply to.\n */\nexport const PageToolbar: React.FC<PageToolbarProps> = ({\n actions = [],\n onBack,\n backLabel = \"Back\",\n className,\n padding = \"md\",\n children,\n}) => {\n return (\n <div className={cn(\"flex items-center gap-2\", paddingClasses[padding], className)}>\n {onBack && (\n <Button\n variant=\"secondary\"\n onClick={onBack}\n aria-label={backLabel}\n leftIcon={<Icon icon={ChevronLeft} size=\"sm\" />}\n iconOnly\n />\n )}\n\n {children && <div className=\"min-w-0 flex-1\">{children}</div>}\n\n <PageToolbarActions actions={actions} className={cn(!children && \"ml-auto\")} />\n </div>\n );\n};\n","import { ChevronDown, ChevronLeft, ChevronRight, ChevronUp, Ellipsis } from \"lucide-react\";\nimport React, {\n useCallback,\n useEffect,\n useMemo,\n useRef,\n useState,\n} from \"react\";\nimport { Button } from \"../action/Button\";\nimport { FilterChip } from \"../action/FilterChip\";\nimport { Checkbox } from \"../input/Checkbox\";\nimport { DatePicker } from \"../input/DatePicker\";\nimport { SearchField } from \"../input/SearchField\";\nimport { Dropdown } from \"../overlays/Dropdown\";\nimport { cn } from \"../utils/cn\";\nimport { Icon } from \"./Icon\";\nimport type { PageHeaderAction } from \"./PageHeader\";\nimport { PageToolbarActions } from \"./PageToolbar\";\n\nexport interface TableColumn<T = any> {\n /** Unique column identifier */\n id: string;\n /** Column header text */\n header: string;\n /** Data accessor - can be string key or function */\n accessor: keyof T | ((row: T) => any);\n /** Custom cell renderer */\n cell?: (value: any, row: T, index: number) => React.ReactNode;\n /** Column width */\n width?: string | number;\n /** Whether column is sortable */\n sortable?: boolean;\n /** Whether column is searchable */\n searchable?: boolean;\n /** Column alignment */\n align?: \"left\" | \"center\" | \"right\";\n /** Whether column is sticky */\n sticky?: \"left\" | \"right\";\n /** Custom header renderer */\n headerCell?: () => React.ReactNode;\n}\n\nexport interface TableAction<T = any> {\n /** Action identifier */\n id: string;\n /** Action label */\n label: string;\n /** Action icon */\n icon?: React.ReactNode;\n /** Action handler */\n onClick: (row: T, index: number) => void;\n /** Whether action is disabled for this row */\n disabled?: (row: T) => boolean;\n /** Action variant */\n variant?: \"primary\" | \"secondary\" | \"outline\" | \"ghost\" | \"destructive\";\n}\n\nexport interface TableFilter {\n /** Filter identifier */\n id: string;\n /** Filter label */\n label: string;\n /** Filter type */\n type?: \"select\" | \"date\" | \"dateRange\";\n /** Leading icon on the chip — what the filter is about, at a glance. */\n icon?: React.ReactNode;\n /** Filter options (for select type) */\n options?: Array<{ value: string; label: string }>;\n /** Current filter value */\n value?: string | Date | null | string[];\n /** Filter change handler */\n onChange: (value: string | Date | null | string[]) => void;\n /** Placeholder text */\n placeholder?: string;\n /** Whether filter is multi-select */\n multiSelect?: boolean;\n}\n\n/**\n * `TableFilter.onChange` covers every filter `type` in one signature, so a\n * handler written for the type it is actually attached to does not fit it\n * (parameters are contravariant). These adapters bridge that without pushing a\n * cast into every call site.\n *\n * The fallbacks are unreachable in practice — a `type: \"date\"` filter only ever\n * emits `Date | null`, a single `type: \"select\"` only ever a string — but they\n * keep the coercion explicit instead of asserting it away.\n */\nexport const dateFilterHandler =\n (fn: (value: Date | null) => void): TableFilter[\"onChange\"] =>\n (value) => fn(value instanceof Date ? value : null);\n\nexport const selectFilterHandler =\n (fn: (value: string) => void): TableFilter[\"onChange\"] =>\n (value) => fn(typeof value === \"string\" ? value : \"\");\n\nexport interface TableProps<T = any> {\n /** Table data */\n data: T[];\n /** Column definitions */\n columns: TableColumn<T>[];\n /** Loading state */\n loading?: boolean;\n /** Whether table is searchable */\n searchable?: boolean;\n /** Search placeholder text */\n searchPlaceholder?: string;\n /**\n * Take over the query. Pass this pair when the page already filters its own\n * data — across fields no column exposes, or together with filters of its\n * own — and only wants the search plate to sit in the toolbar where the\n * design puts it. The built-in column search then stays out of the way;\n * without them the table owns both the box and the filtering.\n */\n searchValue?: string;\n onSearchChange?: (value: string) => void;\n /** Table filters */\n filters?: TableFilter[];\n /**\n * Buttons for the toolbar above the table — \"New …\", import, export. This is\n * where a list's own actions belong: the page header names the page, the\n * table owns what you do to it.\n */\n toolbarActions?: PageHeaderAction[];\n /** Whether table has pagination */\n paginated?: boolean;\n /** Rows per page. Fixed — the footer is a summary and a page list, nothing to set. */\n defaultPageSize?: number;\n /** Row actions */\n actions?: TableAction<T>[];\n /** Row click handler */\n onRowClick?: (row: T, index: number) => void;\n /** Row selection */\n selectable?: boolean;\n /** Selected rows */\n selectedRows?: T[];\n /** Selection change handler */\n onSelectionChange?: (selectedRows: T[]) => void;\n /** Row key accessor */\n getRowKey?: (row: T, index: number) => string | number;\n /** Empty state content */\n emptyContent?: React.ReactNode;\n /**\n * Left-hand line under the table. Defaults to the range/total count on a\n * paginated table; pass a node to say it in the app's own words (\"9 of 1,284\n * contacts\"), which also gives an unpaginated table that one line.\n */\n footerSummary?: React.ReactNode;\n /** Row density. `md` is the default data row; `sm` for a dense inline list. */\n size?: \"sm\" | \"md\" | \"lg\";\n /** Whether to show row hover */\n hoverable?: boolean;\n /** Additional CSS classes */\n className?: string;\n /** Custom row className */\n rowClassName?: (row: T, index: number) => string;\n /**\n * Tint the header row so it reads as a column strip rather than a first row.\n * On by default. Turn it off for a table that already sits on a tinted\n * surface, where a second wash just muddies the edge.\n */\n headerBackground?: boolean;\n /** Horizontal padding inside the table box. */\n padding?: \"none\" | \"sm\" | \"md\" | \"lg\";\n}\n\n/** Cell padding — uniform across columns, so the grid reads as a grid. */\nconst cellPadding = {\n none: \"px-0\",\n sm: \"px-2\",\n md: \"px-3.5\",\n lg: \"px-5\",\n};\n\nconst rowHeights = {\n sm: \"h-row-lg\",\n md: \"h-row-xl\",\n lg: \"h-14\",\n};\n\n/** How many placeholder rows to draw while the data is on its way. */\nconst SKELETON_ROWS = 8;\n\n/** Uneven cell widths, so the placeholder reads as text and not as a bar chart. */\nconst SKELETON_WIDTHS = [\"62%\", \"44%\", \"74%\", \"52%\", \"68%\", \"48%\", \"80%\", \"56%\"];\n\ninterface SortState {\n column: string | null;\n direction: \"asc\" | \"desc\" | null;\n}\n\ninterface PaginationState {\n page: number;\n pageSize: number;\n}\n\n/**\n * Page buttons around the current page: first, last, a window of neighbours,\n * and an ellipsis wherever that skips something.\n */\nfunction pageWindow(current: number, total: number): Array<number | \"gap\"> {\n if (total <= 7) return Array.from({ length: total }, (_, i) => i);\n\n const pages = new Set([0, total - 1, current - 1, current, current + 1]);\n const sorted = [...pages].filter((p) => p >= 0 && p < total).sort((a, b) => a - b);\n\n const out: Array<number | \"gap\"> = [];\n sorted.forEach((page, index) => {\n if (index > 0 && page - (sorted[index - 1] as number) > 1) out.push(\"gap\");\n out.push(page);\n });\n return out;\n}\n\n/** One filter, as a chip that opens its own value list. */\nconst FilterMenu = (props: TableFilter) => {\n const values = Array.isArray(props.value)\n ? props.value\n : props.value != null && props.value !== \"\" && props.value !== \"all\"\n ? [props.value]\n : [];\n\n if (props.type === \"date\") {\n const active = props.value instanceof Date;\n return (\n <DatePicker\n value={props.value as Date | null}\n onChange={(date) => props.onChange(date)}\n placeholder={props.placeholder || props.label}\n // Active is a soft fill, like every other filter — an outline in the\n // accent hue was left over from the blue-accent design and read as a\n // focus ring on a field nobody had focused.\n className={cn(\"min-w-40\", active && \"bg-info-soft text-info-fg\")}\n />\n );\n }\n\n const labelOf = (value: unknown) =>\n props.options?.find((option) => option.value === value)?.label ?? String(value);\n\n const isSelected = (value: string) =>\n Array.isArray(props.value) ? props.value.includes(value) : props.value === value;\n\n const pick = (value: string) => {\n if (!props.multiSelect) return props.onChange(value);\n const current = Array.isArray(props.value) ? props.value : [];\n props.onChange(\n current.includes(value) ? current.filter((v) => v !== value) : [...current, value],\n );\n };\n\n const active = values.length > 0;\n\n return (\n <FilterChip\n tone=\"outline\"\n caret\n icon={props.icon}\n active={active}\n label={active ? `${props.label}: ${values.map(labelOf).join(\", \")}` : props.label}\n title={props.label}\n onClear={() => props.onChange(props.multiSelect ? [] : \"all\")}\n menu={(close) => (\n <div role=\"listbox\" className=\"flex flex-col\">\n {props.options?.map((option) => (\n <button\n key={option.value}\n type=\"button\"\n role=\"option\"\n aria-selected={isSelected(option.value)}\n onClick={() => {\n pick(option.value);\n if (!props.multiSelect) close();\n }}\n className={cn(\n \"flex cursor-pointer items-center gap-2 rounded-md px-2.5 py-1.5 text-left text-sm\",\n \"transition-colors duration-fast ease-out hover:bg-surface-hover\",\n \"focus-visible:outline-none focus-visible:focus-ring\",\n isSelected(option.value) ? \"font-medium text-text\" : \"text-text-muted\",\n )}\n >\n {option.label}\n </button>\n ))}\n </div>\n )}\n />\n );\n};\n\n/**\n * Data table: a bordered box with a tinted column strip, a toolbar above it\n * (search, filters, the list's own actions) and a summary + paginator below.\n */\nexport const Table = <T extends Record<string, any>>({\n data,\n columns,\n loading = false,\n searchable = false,\n searchPlaceholder = \"Search...\",\n searchValue,\n onSearchChange,\n filters = [],\n toolbarActions = [],\n paginated = false,\n defaultPageSize = 10,\n actions = [],\n onRowClick,\n selectable = false,\n selectedRows = [],\n onSelectionChange,\n getRowKey = (row, index) => index,\n emptyContent,\n footerSummary,\n size = \"md\",\n hoverable = true,\n padding = \"md\",\n className,\n rowClassName,\n headerBackground = true,\n}: TableProps<T>) => {\n const [internalSearch, setInternalSearch] = useState(\"\");\n const controlledSearch = searchValue !== undefined;\n const searchTerm = controlledSearch ? searchValue : internalSearch;\n const setSearchTerm = onSearchChange ?? setInternalSearch;\n const [sortState, setSortState] = useState<SortState>({\n column: null,\n direction: null,\n });\n const [pagination, setPagination] = useState<PaginationState>({\n page: 0,\n pageSize: defaultPageSize,\n });\n\n const tableRef = useRef<HTMLTableElement>(null);\n\n // Memoized filtered data\n const filteredData = useMemo(() => {\n let result = data;\n\n // Apply search filter — unless the owner took over the query, in which case\n // the data arriving here is already filtered and doing it again would\n // narrow it to whatever the columns happen to expose.\n if (searchable && !controlledSearch && searchTerm.trim()) {\n const searchableColumns = columns.filter(\n (col) => col.searchable !== false\n );\n const lowerSearchTerm = searchTerm.toLowerCase();\n\n result = result.filter((row) => {\n return searchableColumns.some((column) => {\n const value =\n typeof column.accessor === \"function\"\n ? column.accessor(row)\n : row[column.accessor];\n\n return String(value || \"\")\n .toLowerCase()\n .includes(lowerSearchTerm);\n });\n });\n }\n\n // Apply column filters\n filters.forEach((filter) => {\n if (filter.value && filter.value !== \"all\") {\n result = result.filter((row) => {\n const column = columns.find((col) => col.id === filter.id);\n if (!column) return true;\n\n const value =\n typeof column.accessor === \"function\"\n ? column.accessor(row)\n : row[column.accessor];\n\n return String(value || \"\") === filter.value;\n });\n }\n });\n\n return result;\n }, [data, searchTerm, controlledSearch, columns, searchable, filters]);\n\n // Memoized sorted data\n const sortedData = useMemo(() => {\n if (!sortState.column || !sortState.direction) return filteredData;\n\n const column = columns.find((col) => col.id === sortState.column);\n if (!column) return filteredData;\n\n return [...filteredData].sort((a, b) => {\n const aValue =\n typeof column.accessor === \"function\"\n ? column.accessor(a)\n : a[column.accessor];\n const bValue =\n typeof column.accessor === \"function\"\n ? column.accessor(b)\n : b[column.accessor];\n\n let comparison = 0;\n\n if (aValue < bValue) comparison = -1;\n else if (aValue > bValue) comparison = 1;\n\n return sortState.direction === \"desc\" ? -comparison : comparison;\n });\n }, [filteredData, sortState, columns]);\n\n // Memoized paginated data\n const paginatedData = useMemo(() => {\n if (!paginated) return sortedData;\n\n const startIndex = pagination.page * pagination.pageSize;\n const endIndex = startIndex + pagination.pageSize;\n return sortedData.slice(startIndex, endIndex);\n }, [sortedData, pagination, paginated]);\n\n // Handle sorting\n const handleSort = useCallback(\n (columnId: string) => {\n const column = columns.find((col) => col.id === columnId);\n if (!column?.sortable) return;\n\n setSortState((prev) => {\n if (prev.column !== columnId) {\n return { column: columnId, direction: \"asc\" };\n }\n if (prev.direction === \"asc\") {\n return { column: columnId, direction: \"desc\" };\n }\n return { column: null, direction: null };\n });\n },\n [columns]\n );\n\n // Handle pagination\n const handlePageChange = useCallback((newPage: number) => {\n setPagination((prev) => ({ ...prev, page: newPage }));\n }, []);\n\n // Handle selection\n const handleRowSelection = useCallback(\n (row: T, checked: boolean) => {\n if (!onSelectionChange) return;\n\n const rowKey = getRowKey(row, 0);\n if (checked) {\n onSelectionChange([...selectedRows, row]);\n } else {\n onSelectionChange(\n selectedRows.filter(\n (_, i) => getRowKey(selectedRows[i], i) !== rowKey\n )\n );\n }\n },\n [selectedRows, onSelectionChange, getRowKey]\n );\n\n const handleSelectAll = useCallback(\n (checked: boolean) => {\n if (!onSelectionChange) return;\n onSelectionChange(checked ? [...paginatedData] : []);\n },\n [paginatedData, onSelectionChange]\n );\n\n // Reset pagination when data changes\n useEffect(() => {\n setPagination((prev) => ({ ...prev, page: 0 }));\n }, [searchTerm, sortState]);\n\n // Separate effect for filters to avoid infinite loops\n useEffect(() => {\n setPagination((prev) => ({ ...prev, page: 0 }));\n }, [filters.map((f) => f.value).join(\",\")]);\n\n // Calculate pagination info\n const totalItems = sortedData.length;\n const totalPages = Math.ceil(totalItems / pagination.pageSize);\n const startItem = pagination.page * pagination.pageSize + 1;\n const endItem = Math.min(startItem + pagination.pageSize - 1, totalItems);\n\n // Check if all visible rows are selected\n const allVisibleSelected =\n paginatedData.length > 0 &&\n paginatedData.every((row) => {\n const rowKey = getRowKey(row, 0);\n return selectedRows.some(\n (selectedRow, i) => getRowKey(selectedRow, i) === rowKey\n );\n });\n\n const someVisibleSelected = paginatedData.some((row) => {\n const rowKey = getRowKey(row, 0);\n return selectedRows.some(\n (selectedRow, i) => getRowKey(selectedRow, i) === rowKey\n );\n });\n\n const pad = cellPadding[padding];\n\n // Sticky cells need the same fill as the strip they sit in, otherwise the\n // frozen column shows the page through while the rest of the row is tinted.\n const headerFill = headerBackground ? \"bg-surface-sunk\" : \"bg-surface\";\n\n const cellClasses = cn(\"text-text\", pad);\n const showToolbar = searchable || filters.length > 0 || toolbarActions.length > 0;\n const showPaginator = paginated && totalItems > 0;\n const showFooter = showPaginator || footerSummary !== undefined;\n\n return (\n <div className={cn(\"flex min-w-0 flex-col\", className)}>\n {showToolbar && (\n <div className=\"flex flex-wrap items-center gap-2 pb-3\">\n {searchable && (\n <SearchField\n value={searchTerm}\n onValueChange={setSearchTerm}\n placeholder={searchPlaceholder}\n containerClassName=\"w-full sm:w-66\"\n />\n )}\n\n {filters.map((filter) => (\n <FilterMenu key={filter.id} {...filter} />\n ))}\n\n {toolbarActions.length > 0 && (\n <PageToolbarActions actions={toolbarActions} className=\"ml-auto\" />\n )}\n </div>\n )}\n\n {/* A bordered box, not a bare grid: the table has to hold its own edge\n now that the page around it is one undivided card. */}\n <div className=\"relative w-full overflow-x-auto rounded-lg ring-1 ring-border\">\n {/**\n * The skeleton lives in the tbody, not above the table.\n *\n * It used to render a whole `ContentLoading` — which defaults to\n * `variant=\"page\"`, so a `<main>` landmark with page padding appeared\n * *inside* this box — centred above a `<thead>` whose headers were\n * suppressed. The result had neither the table's columns nor its row\n * height, and the real rows then shoved everything into place.\n *\n * The headers are known before the data is, so they stay; only the rows\n * are unknown, and those are drawn at row height in the real columns.\n */}\n <table ref={tableRef} className=\"min-w-full border-collapse text-base text-text\">\n <thead className={cn(headerFill, \"h-control-lg\")}>\n <tr>\n {/* Selection Column */}\n {selectable && (\n <th className={cn(cellClasses, \"w-10\")}>\n <Checkbox\n size=\"sm\"\n checked={allVisibleSelected}\n indeterminate={someVisibleSelected && !allVisibleSelected}\n onChange={(e) => handleSelectAll(e.target.checked)}\n aria-label=\"Select all rows\"\n />\n </th>\n )}\n\n {/* Data Columns */}\n {columns.map((column) => (\n <th\n key={column.id}\n className={cn(\n cellClasses,\n \"text-xs font-semibold uppercase tracking-label text-text-muted\",\n \"group\",\n {\n \"text-left\": column.align === \"left\" || !column.align,\n \"text-center\": column.align === \"center\",\n \"text-right\": column.align === \"right\",\n \"cursor-pointer select-none\": column.sortable,\n [`sticky left-0 ${headerFill}`]:\n column.sticky === \"left\",\n [`sticky right-0 ${headerFill}`]:\n column.sticky === \"right\",\n },\n )}\n style={{ width: column.width }}\n onClick={() => column.sortable && handleSort(column.id)}\n >\n <div className=\"flex items-center gap-1.5\">\n {column.headerCell ? column.headerCell() : column.header}\n {column.sortable && (\n <Icon\n icon={\n sortState.column === column.id && sortState.direction === \"desc\"\n ? ChevronDown\n : ChevronUp\n }\n size=\"xs\"\n className={cn(\n \"transition-opacity duration-fast ease-out\",\n sortState.column === column.id\n ? \"text-text opacity-100\"\n : \"text-text-subtle opacity-0 group-hover:opacity-100\",\n )}\n />\n )}\n </div>\n </th>\n ))}\n\n {/* Actions Column */}\n {actions.length > 0 && (\n <th className={cn(cellClasses, \"w-10\")}>\n <span className=\"sr-only\">Actions</span>\n </th>\n )}\n </tr>\n </thead>\n\n <tbody>\n {loading\n ? Array.from({ length: SKELETON_ROWS }).map((_, rowIndex) => (\n <tr key={`skeleton-${rowIndex}`} className=\"animate-pulse border-t border-border-subtle\" aria-hidden>\n {selectable && (\n <td className={cn(cellClasses, \"h-row-lg\")}>\n <span className=\"block size-4 rounded-xs bg-surface-hover\" />\n </td>\n )}\n {columns.map((column, columnIndex) => (\n <td key={column.id} className={cn(cellClasses, \"h-row-lg\")} style={{ width: column.width }}>\n <span\n className=\"block h-3 rounded-xs bg-surface-hover\"\n // Uneven widths, so a column of placeholders reads as\n // text rather than as a set of progress bars.\n style={{ width: SKELETON_WIDTHS[(rowIndex + columnIndex) % SKELETON_WIDTHS.length] }}\n />\n </td>\n ))}\n {actions.length > 0 && <td className={cn(cellClasses, \"h-row-lg\")} />}\n </tr>\n ))\n : paginatedData.length === 0\n ? (\n <tr>\n <td\n colSpan={\n columns.length +\n (selectable ? 1 : 0) +\n (actions.length > 0 ? 1 : 0)\n }\n className={cn(\n cellClasses,\n \"border-t border-border-subtle py-10 text-center text-text-muted\"\n )}\n >\n {emptyContent || \"No data available\"}\n </td>\n </tr>\n )\n : paginatedData.map((row, index) => {\n const rowKey = getRowKey(row, index);\n const isSelected = selectedRows.some(\n (selectedRow, i) => getRowKey(selectedRow, i) === rowKey\n );\n\n return (\n <tr\n key={rowKey}\n className={cn(\n rowHeights[size],\n // Hairline above every row, including the first: it is\n // what separates the body from the column strip.\n \"border-t border-border-subtle\",\n hoverable && \"transition-colors duration-fast ease-out hover:bg-surface-hover\",\n onRowClick && \"cursor-pointer\",\n isSelected && \"bg-accent-soft\",\n rowClassName?.(row, index)\n )}\n onClick={(e) => {\n e.stopPropagation();\n onRowClick?.(row, index);\n }}\n >\n {/* Selection Cell */}\n {selectable && (\n <td className={cellClasses}>\n <Checkbox\n size=\"sm\"\n checked={isSelected}\n onClick={(e) => e.stopPropagation()}\n onChange={(e) => {\n e.stopPropagation();\n handleRowSelection(row, e.target.checked);\n }}\n aria-label=\"Select row\"\n />\n </td>\n )}\n\n {/* Data Cells */}\n {columns.map((column) => {\n const value =\n typeof column.accessor === \"function\"\n ? column.accessor(row)\n : row[column.accessor];\n\n return (\n <td\n key={column.id}\n className={cn(cellClasses, {\n \"text-left\":\n column.align === \"left\" || !column.align,\n \"text-center\": column.align === \"center\",\n \"text-right\": column.align === \"right\",\n \"sticky left-0 bg-surface\":\n column.sticky === \"left\",\n \"sticky right-0 bg-surface\":\n column.sticky === \"right\",\n })}\n >\n {column.cell\n ? column.cell(value, row, index)\n : String(value || \"\")}\n </td>\n );\n })}\n\n {/* Actions Cell */}\n {actions.length > 0 && (\n <td className={cellClasses}>\n <Dropdown\n className=\"rounded-md\"\n trigger={\n <span className=\"grid size-7 place-items-center text-text-subtle\">\n <Icon icon={Ellipsis} size=\"md\" color=\"current\" />\n </span>\n }\n options={actions.map((action) => ({\n value: action.id,\n label: action.label,\n icon: action.icon,\n disabled: action.disabled?.(row),\n }))}\n onSelect={(actionId) => {\n const action = actions.find(\n (a) => a.id === actionId\n );\n if (action) {\n action.onClick(row, index);\n }\n }}\n placement=\"bottom-end\"\n />\n </td>\n )}\n </tr>\n );\n })}\n </tbody>\n </table>\n </div>\n\n {showFooter && (\n <div className=\"flex flex-wrap items-center gap-3 px-1 pt-3 text-xs text-text-muted\">\n <span className=\"min-w-0 flex-1\">\n {footerSummary ?? `Showing ${startItem}–${endItem} of ${totalItems}`}\n </span>\n\n {showPaginator && <div className=\"flex items-center gap-0.5\">\n <Button\n size=\"xs\"\n variant=\"ghost\"\n iconOnly\n aria-label=\"Previous page\"\n onClick={() => handlePageChange(pagination.page - 1)}\n disabled={pagination.page === 0}\n >\n <Icon icon={ChevronLeft} size=\"md\" color=\"current\" />\n </Button>\n\n {pageWindow(pagination.page, totalPages).map((entry, index) =>\n entry === \"gap\" ? (\n <span key={`gap-${index}`} className=\"px-1 text-text-subtle\">\n …\n </span>\n ) : (\n <button\n key={entry}\n type=\"button\"\n aria-current={entry === pagination.page ? \"page\" : undefined}\n onClick={() => handlePageChange(entry)}\n className={cn(\n \"h-control-xs min-w-6 cursor-pointer rounded-sm px-1.5 tabular-nums\",\n \"transition-colors duration-fast ease-out\",\n \"focus-visible:outline-none focus-visible:focus-ring\",\n entry === pagination.page\n ? \"bg-surface-sunk font-semibold text-text\"\n : \"text-text-muted hover:bg-surface-hover hover:text-text\",\n )}\n >\n {entry + 1}\n </button>\n ),\n )}\n\n <Button\n size=\"xs\"\n variant=\"ghost\"\n iconOnly\n aria-label=\"Next page\"\n onClick={() => handlePageChange(pagination.page + 1)}\n disabled={pagination.page >= totalPages - 1}\n >\n <Icon icon={ChevronRight} size=\"md\" color=\"current\" />\n </Button>\n </div>}\n </div>\n )}\n </div>\n );\n};\n","import React, { createContext, useContext, useState } from 'react';\nimport { cn } from '../utils/cn';\n\nexport interface TabItem {\n /** Tab identifier */\n id: string;\n /** Tab label */\n label: string;\n /** Tab content */\n content?: React.ReactNode;\n /** Whether tab is disabled */\n disabled?: boolean;\n /** Badge/count to show next to label */\n badge?: string | number;\n}\n\nexport interface TabsProps {\n /** Tab items */\n items: TabItem[];\n /** Default active tab */\n defaultTab?: string;\n /** Active tab (controlled) */\n activeTab?: string;\n /** Tab change handler */\n onTabChange?: (tabId: string) => void;\n /** Tabs variant */\n variant?: 'default' | 'pills' | 'underline';\n /** Tabs size */\n size?: 'sm' | 'md' | 'lg';\n /** Additional CSS classes */\n className?: string;\n}\n\nexport interface TabBarProps {\n /** Tab items (simplified for bar style) */\n items: Array<{\n id: string;\n label: string;\n badge?: string | number;\n disabled?: boolean;\n }>;\n /** Active tab */\n activeTab?: string;\n /** Tab change handler */\n onTabChange?: (tabId: string) => void;\n /** Additional CSS classes */\n className?: string;\n}\n\nconst TabsContext = createContext<{\n activeTab: string;\n setActiveTab: (tab: string) => void;\n} | null>(null);\n\n/**\n * TabBar component for simple tab navigation (like in the screenshot)\n */\nexport const TabBar: React.FC<TabBarProps> = ({\n items,\n activeTab,\n onTabChange,\n className,\n}) => {\n const [internalActiveTab, setInternalActiveTab] = useState(items[0]?.id || '');\n const currentActiveTab = activeTab || internalActiveTab;\n\n const handleTabClick = (tabId: string) => {\n if (onTabChange) {\n onTabChange(tabId);\n } else {\n setInternalActiveTab(tabId);\n }\n };\n\n return (\n <div className={cn('border-b border-border', className)}>\n <nav className=\"-mb-px flex space-x-8\">\n {items.map((item) => (\n <button\n key={item.id}\n onClick={() => !item.disabled && handleTabClick(item.id)}\n disabled={item.disabled}\n className={cn(\n 'border-b-2 py-2 px-1 text-sm font-medium transition-colors duration-fast',\n {\n 'border-accent-border text-text': currentActiveTab === item.id,\n 'border-transparent text-text-muted hover:text-text':\n currentActiveTab !== item.id && !item.disabled,\n 'border-transparent text-text-disabled cursor-not-allowed': item.disabled,\n }\n )}\n >\n <span className=\"flex items-center gap-2\">\n {item.label}\n {item.badge && (\n <span className={cn(\n 'inline-flex items-center px-2 py-0.5 rounded-full text-xs font-medium',\n currentActiveTab === item.id\n ? 'bg-accent-soft text-accent'\n : 'bg-surface-hover text-text-muted'\n )}>\n {item.badge}\n </span>\n )}\n </span>\n </button>\n ))}\n </nav>\n </div>\n );\n};\n\n/**\n * Full Tabs component with content panels\n */\nexport const Tabs: React.FC<TabsProps> = ({\n items,\n defaultTab,\n activeTab,\n onTabChange,\n variant = 'default',\n size = 'md',\n className,\n}) => {\n const [internalActiveTab, setInternalActiveTab] = useState(\n defaultTab || activeTab || items[0]?.id || ''\n );\n\n const currentActiveTab = activeTab || internalActiveTab;\n\n const handleTabChange = (tabId: string) => {\n if (onTabChange) {\n onTabChange(tabId);\n } else {\n setInternalActiveTab(tabId);\n }\n };\n\n const contextValue = {\n activeTab: currentActiveTab,\n setActiveTab: handleTabChange,\n };\n\n const activeTabItem = items.find(item => item.id === currentActiveTab);\n\n const tabListClasses = cn(\n 'flex',\n {\n 'border-b border-border px-2': variant === 'default' || variant === 'underline',\n 'bg-surface-hover p-1 rounded-lg': variant === 'pills',\n 'space-x-1': variant === 'pills',\n 'space-x-8': variant === 'default' || variant === 'underline',\n },\n className\n );\n\n const tabClasses = (item: TabItem, isActive: boolean) => {\n const baseClasses = 'transition-colors duration-fast font-medium';\n\n const sizeClasses = {\n 'text-xs px-2 py-1': size === 'sm',\n 'text-sm px-3 py-2': size === 'md',\n 'text-base px-4 py-3': size === 'lg',\n };\n\n const variantClasses = {\n // Default variant\n 'border-b-2 -mb-px': variant === 'default',\n // Pills variant\n 'rounded-md': variant === 'pills',\n // Underline variant\n 'border-b-2 pb-2': variant === 'underline',\n };\n\n const stateClasses = {\n 'opacity-50 cursor-not-allowed': item.disabled,\n 'cursor-pointer': !item.disabled,\n };\n\n // Active state classes\n const activeClasses = isActive ? {\n 'border-accent-border text-text': variant === 'default' || variant === 'underline',\n 'bg-surface text-text shadow-none': variant === 'pills',\n } : {};\n\n // Non-active, non-disabled state classes\n const inactiveClasses = !isActive && !item.disabled ? {\n 'border-transparent text-text-muted hover:text-text': variant === 'default',\n 'text-text-muted hover:text-text': variant === 'pills',\n 'border-transparent text-text-muted hover:text-text hover:border-border': variant === 'underline',\n } : {};\n\n return cn(baseClasses, sizeClasses, variantClasses, stateClasses, activeClasses, inactiveClasses);\n };\n\n return (\n <TabsContext.Provider value={contextValue}>\n <div>\n {/* Tab List */}\n <div className={tabListClasses} role=\"tablist\">\n {items.map((item) => (\n <button\n key={item.id}\n type=\"button\"\n role=\"tab\"\n aria-selected={currentActiveTab === item.id}\n aria-controls={`tabpanel-${item.id}`}\n disabled={item.disabled}\n onClick={() => !item.disabled && handleTabChange(item.id)}\n className={tabClasses(item, currentActiveTab === item.id)}\n >\n <span className=\"flex items-center gap-2\">\n {item.label}\n {item.badge && (\n <span className=\"inline-flex items-center px-2 py-0.5 rounded-full text-xs font-medium bg-surface-hover text-text-muted\">\n {item.badge}\n </span>\n )}\n </span>\n </button>\n ))}\n </div>\n\n {/* Tab Content */}\n {activeTabItem?.content && (\n <div\n role=\"tabpanel\"\n id={`tabpanel-${currentActiveTab}`}\n aria-labelledby={`tab-${currentActiveTab}`}\n className=\"mt-4\"\n >\n {activeTabItem.content}\n </div>\n )}\n </div>\n </TabsContext.Provider>\n );\n};\n\n/**\n * Hook to access tab context\n */\nexport const useTabsContext = () => {\n const context = useContext(TabsContext);\n if (!context) {\n throw new Error('useTabsContext must be used within a Tabs component');\n }\n return context;\n}; ","import React, { useEffect, useRef } from 'react';\nimport { X } from \"lucide-react\";\nimport { Icon } from \"../content/Icon\";\nimport { cn } from '../utils/cn';\n\nexport interface ModalProps {\n /**\n * Whether the modal is open\n */\n open: boolean;\n \n /**\n * Callback fired when the modal should be closed\n */\n onClose: () => void;\n \n /**\n * The title of the modal\n */\n title?: string;\n \n /**\n * The size of the modal\n */\n size?: 'sm' | 'md' | 'lg' | 'xl' | 'full';\n \n /**\n * Whether clicking the backdrop should close the modal\n */\n closeOnBackdropClick?: boolean;\n \n /**\n * Whether pressing escape should close the modal\n */\n closeOnEscape?: boolean;\n \n /**\n * Additional class name for the modal content\n */\n className?: string;\n \n /**\n * Additional class name for the modal backdrop\n */\n backdropClassName?: string;\n \n /**\n * The content of the modal\n */\n children: React.ReactNode;\n \n /**\n * Footer content for the modal\n */\n footer?: React.ReactNode;\n \n /**\n * Whether to show the close button\n */\n showCloseButton?: boolean;\n}\n\nconst modalSizes = {\n sm: 'max-w-md',\n md: 'max-w-lg',\n lg: 'max-w-2xl',\n xl: 'max-w-4xl',\n full: 'max-w-full mx-4',\n};\n\n/**\n * Modal component with theme integration and accessibility features\n * \n * @example\n * ```tsx\n * <Modal\n * open={isOpen}\n * onClose={() => setIsOpen(false)}\n * title=\"Confirm Action\"\n * size=\"md\"\n * >\n * <p>Are you sure you want to delete this item?</p>\n * </Modal>\n * \n * <Modal\n * open={isOpen}\n * onClose={() => setIsOpen(false)}\n * title=\"Settings\"\n * size=\"lg\"\n * footer={\n * <div className=\"flex justify-end space-x-2\">\n * <Button variant=\"outline\" onClick={() => setIsOpen(false)}>\n * Cancel\n * </Button>\n * <Button onClick={handleSave}>\n * Save\n * </Button>\n * </div>\n * }\n * >\n * <SettingsForm />\n * </Modal>\n * ```\n */\nexport function Modal({\n open,\n onClose,\n title,\n size = 'md',\n closeOnBackdropClick = true,\n closeOnEscape = true,\n className,\n backdropClassName,\n children,\n footer,\n showCloseButton = true,\n}: ModalProps) {\n const modalRef = useRef<HTMLDivElement>(null);\n const previousActiveElement = useRef<HTMLElement | null>(null);\n\n // Handle escape key\n useEffect(() => {\n if (!open || !closeOnEscape) return;\n\n const handleEscape = (event: KeyboardEvent) => {\n if (event.key === 'Escape') {\n onClose();\n }\n };\n\n document.addEventListener('keydown', handleEscape);\n return () => document.removeEventListener('keydown', handleEscape);\n }, [open, closeOnEscape, onClose]);\n\n // Handle focus management\n useEffect(() => {\n if (open) {\n // Store the currently focused element\n previousActiveElement.current = document.activeElement as HTMLElement;\n \n // Focus the modal\n if (modalRef.current) {\n modalRef.current.focus();\n }\n \n // Prevent body scroll\n document.body.style.overflow = 'hidden';\n } else {\n // Restore focus to the previously focused element\n if (previousActiveElement.current) {\n previousActiveElement.current.focus();\n }\n \n // Restore body scroll\n document.body.style.overflow = '';\n }\n\n return () => {\n document.body.style.overflow = '';\n };\n }, [open]);\n\n // Handle backdrop click\n const handleBackdropClick = (event: React.MouseEvent) => {\n if (closeOnBackdropClick && event.target === event.currentTarget) {\n onClose();\n }\n };\n\n if (!open) return null;\n\n return (\n <div\n className={cn(\n 'fixed inset-0 z-modal flex items-center justify-center p-4',\n 'bg-scrim',\n // 'animate-fade-in',\n backdropClassName\n )}\n onClick={handleBackdropClick}\n >\n <div\n ref={modalRef}\n className={cn(\n 'relative w-full bg-surface rounded-lg shadow-modal',\n // 'animate-scale-in',\n 'focus:outline-none',\n modalSizes[size],\n className\n )}\n role=\"dialog\"\n aria-modal=\"true\"\n aria-labelledby={title ? 'modal-title' : undefined}\n tabIndex={-1}\n >\n {/* Header */}\n {(title || showCloseButton) && (\n <div className=\"flex items-center justify-between p-6 pb-0\">\n {title && (\n <span\n id=\"modal-title\"\n className=\"text-lg font-semibold text-text\"\n >\n {title}\n </span>\n )}\n \n {showCloseButton && (\n <button\n onClick={onClose}\n className=\"p-1 text-text-muted hover:text-text transition-colors\"\n aria-label=\"Close modal\"\n >\n <Icon icon={X} size=\"lg\" color=\"current\" />\n </button>\n )}\n </div>\n )}\n\n {/* Content */}\n <div className=\"p-6\">\n {children}\n </div>\n\n {/* Footer */}\n {footer && (\n <div className=\"px-6 py-4\">\n {footer}\n </div>\n )}\n </div>\n </div>\n );\n} ","import { FilePointer, VirtualMount } from '@opencxh/domain';\nimport { ArrowLeft, FileText, Folder, FolderPlus, HardDrive, Search, Upload, X } from 'lucide-react';\nimport React, { useEffect, useMemo, useRef, useState } from 'react';\nimport { Button } from '../action/Button';\nimport { Icon } from '../content/Icon';\nimport { Table, TableColumn } from '../content/Table';\nimport { Tabs } from '../navigation/Tabs';\nimport { Modal } from '../overlays/Modal';\nimport { Text } from '../typography/Text';\nimport { cn } from '../utils/cn';\nimport { TextField } from './TextField';\n\nexport interface StorageInputProps {\n value?: string | FilePointer;\n onChange: (value: FilePointer | null, content?: Uint8Array) => void;\n label?: string;\n placeholder?: string;\n error?: string;\n disabled?: boolean;\n accept?: string;\n onListFiles?: (filters?: { name?: string; mimeType?: string; mountId?: string, path?: string }) => Promise<{ data: FilePointer[] }> | undefined;\n onListMounts?: () => Promise<{ data: VirtualMount[] }> | undefined;\n onUploadFile?: (payload: { file: Uint8Array; filename: string; mimeType: string; mountId?: string; path?: string }) => Promise<{ data: FilePointer }> | undefined;\n onDownloadFile?: (fileId: string) => Promise<Uint8Array> | undefined;\n onRegisterFile?: (payload: Omit<FilePointer, 'id'>) => Promise<{ data: FilePointer }> | undefined;\n}\n\nexport const StorageInput: React.FC<StorageInputProps> = ({\n value,\n onChange,\n label,\n placeholder = \"Select or upload a file\",\n error,\n disabled,\n accept,\n onListFiles,\n onListMounts,\n onUploadFile,\n onDownloadFile,\n onRegisterFile,\n}) => {\n const [isModalOpen, setIsModalOpen] = useState(false);\n const [mounts, setMounts] = useState<VirtualMount[]>([]);\n const [selectedMount, setSelectedMount] = useState<VirtualMount | null>(null);\n const [currentPath, setCurrentPath] = useState<string>(\"/\");\n const [remoteFiles, setRemoteFiles] = useState<FilePointer[]>([]);\n const [loading, setLoading] = useState(false);\n const [searchTerm, setSearchTerm] = useState(\"\");\n const [selectedPointer, setSelectedPointer] = useState<FilePointer | null>(\n typeof value === 'object' ? value : null\n );\n const [isCreatingFolder, setIsCreatingFolder] = useState(false);\n const [newFolderName, setNewFolderName] = useState(\"\");\n\n const fileInputRef = useRef<HTMLInputElement>(null);\n\n // Load mounts when modal opens\n useEffect(() => {\n if (isModalOpen) {\n loadMounts();\n }\n }, [isModalOpen]);\n\n // Load files when a mount is selected or search term changes\n useEffect(() => {\n if (isModalOpen && selectedMount) {\n loadFiles();\n }\n }, [isModalOpen, selectedMount, currentPath, searchTerm]);\n\n const loadMounts = async () => {\n setLoading(true);\n try {\n const resp = await onListMounts?.();\n if (resp?.data) {\n setMounts(resp.data);\n }\n } catch (err) {\n console.error(\"Failed to load mounts\", err);\n } finally {\n setLoading(false);\n }\n };\n\n const loadFiles = async () => {\n if (!selectedMount) return;\n setLoading(true);\n try {\n const resp = await onListFiles?.({ mountId: selectedMount.id, name: searchTerm, path: currentPath });\n if (resp?.data) {\n setRemoteFiles(resp.data);\n }\n } catch (err) {\n console.error(\"Failed to load files\", err);\n } finally {\n setLoading(false);\n }\n };\n\n const handleLocalOnlySelection = async (e: React.ChangeEvent<HTMLInputElement>) => {\n const file = e.target.files?.[0];\n if (!file) return;\n\n setLoading(true);\n try {\n const buffer = await file.arrayBuffer();\n const content = new Uint8Array(buffer);\n\n const virtualPointer: FilePointer = {\n id: `local-${Date.now()}`,\n name: file.name,\n type: 'file',\n path: '/',\n mimeType: file.type || 'application/octet-stream',\n size: file.size,\n mountId: 'local',\n providerKey: file.name,\n ownerId: 'me',\n };\n\n setSelectedPointer(virtualPointer);\n onChange(virtualPointer, content);\n setIsModalOpen(false);\n } catch (err) {\n console.error(\"Local file selection failed\", err);\n } finally {\n setLoading(false);\n }\n };\n\n const handleUploadToStorage = async (e: React.ChangeEvent<HTMLInputElement>) => {\n const file = e.target.files?.[0];\n if (!file || !selectedMount) return;\n\n setLoading(true);\n try {\n const buffer = await file.arrayBuffer();\n const resp = await onUploadFile?.({\n file: new Uint8Array(buffer),\n filename: file.name,\n mimeType: file.type || 'application/octet-stream',\n mountId: selectedMount.id,\n path: currentPath,\n });\n\n if (resp?.data) {\n const pointer = resp.data;\n setSelectedPointer(pointer);\n onChange(pointer, new Uint8Array(buffer));\n setIsModalOpen(false);\n }\n } catch (err) {\n console.error(\"Upload failed\", err);\n } finally {\n setLoading(false);\n }\n };\n\n const handleCreateFolder = async () => {\n if (!newFolderName || !selectedMount) return;\n\n setLoading(true);\n try {\n const fullPath = `${currentPath}${newFolderName}/`;\n\n if (onRegisterFile) {\n await onRegisterFile({\n name: newFolderName,\n type: 'folder',\n path: currentPath,\n mimeType: 'application/x-directory',\n size: 0,\n mountId: selectedMount.id,\n providerKey: fullPath,\n ownerId: 'me',\n });\n await loadFiles();\n }\n\n setIsCreatingFolder(false);\n setNewFolderName(\"\");\n } catch (err) {\n console.error(\"Failed to create folder\", err);\n } finally {\n setLoading(false);\n }\n };\n\n const handleSelectRemote = async (pointer: FilePointer) => {\n setLoading(true);\n try {\n const content = await onDownloadFile?.(pointer.id);\n setSelectedPointer(pointer);\n onChange(pointer, content);\n setIsModalOpen(false);\n } catch (err) {\n console.error(\"Failed to download file\", err);\n } finally {\n setLoading(false);\n }\n };\n\n const handleClear = (e: React.MouseEvent) => {\n e.stopPropagation();\n setSelectedPointer(null);\n onChange(null);\n };\n\n // Folder & File calculation logic\n const explorerItems = useMemo(() => {\n const folders = new Set<string>();\n const files: FilePointer[] = [];\n\n remoteFiles.forEach(file => {\n if (file.type === 'folder') {\n if (file.path === currentPath) {\n folders.add(file.name);\n }\n return;\n }\n\n const path = file.providerKey || file.name;\n const relativePath = currentPath ? path.substring(currentPath.length) : path;\n const parts = relativePath.split('/').filter(p => p !== \"\");\n\n if (parts.length > 1) {\n folders.add(parts[0]);\n } else if (parts.length === 1) {\n files.push(file);\n }\n });\n\n return {\n folders: Array.from(folders).sort(),\n files: files.sort((a, b) => a.name.localeCompare(b.name))\n };\n }, [remoteFiles, currentPath]);\n\n const handleFolderClick = (folderName: string) => {\n setCurrentPath(prev => `${prev}${folderName}/`);\n };\n\n const handleGoBack = () => {\n const parts = currentPath.split('/').filter(p => p !== \"\");\n parts.pop();\n if (parts.length === 0) {\n setCurrentPath(\"/\");\n } else {\n setCurrentPath(`${parts.join('/')}/`);\n }\n };\n\n const tableData = useMemo(() => {\n const data: any[] = explorerItems.folders.map(f => ({\n id: `folder-${f}`,\n name: f,\n type: 'folder'\n }));\n\n explorerItems.files.forEach(f => {\n data.push({\n ...f,\n type: 'file'\n });\n });\n\n return data;\n }, [explorerItems]);\n\n const explorerColumns: TableColumn<any>[] = [\n {\n id: 'name',\n header: 'Name',\n accessor: 'name',\n cell: (val, row) => (\n <div className=\"flex items-center gap-2\">\n <Icon\n icon={row.type === 'folder' ? Folder : FileText}\n size=\"sm\"\n color={row.type === 'folder' ? \"warning\" : \"secondary\"}\n />\n <span className={cn(row.type === 'folder' && \"font-medium\")}>{val}</span>\n </div>\n )\n },\n {\n id: 'type',\n header: 'Type',\n accessor: (row) => row.type === 'folder' ? 'Folder' : row.mimeType,\n },\n {\n id: 'size',\n header: 'Size',\n accessor: (row) => row.type === 'file' ? `${(row.size / 1024).toFixed(1)} KB` : '-',\n },\n {\n id: 'actions',\n header: '',\n accessor: 'id',\n align: 'right',\n cell: (_, row) => (\n <Button\n variant=\"outline\"\n onClick={(e) => {\n e.stopPropagation();\n row.type === 'folder' ? handleFolderClick(row.name) : handleSelectRemote(row);\n }}\n loading={loading && row.type === 'file' && selectedPointer?.id === row.id}\n >\n {row.type === 'folder' ? 'Open' : 'Select'}\n </Button>\n )\n }\n ];\n\n const mountColumns: TableColumn<VirtualMount>[] = [\n {\n id: 'name',\n header: 'Mount Name',\n accessor: 'name',\n cell: (val) => (\n <div className=\"flex items-center gap-2 font-medium\">\n <Icon icon={HardDrive} size=\"sm\" color=\"primary\" />\n <span>{val}</span>\n </div>\n )\n },\n {\n id: 'actions',\n header: '',\n accessor: 'id',\n align: 'right',\n cell: (_, row) => (\n <Button variant=\"outline\" onClick={() => setSelectedMount(row)}>\n Open\n </Button>\n )\n }\n ];\n\n return (\n <div className=\"space-y-1\">\n {label && (\n <Text variant=\"label\" size=\"sm\" weight=\"medium\">\n {label}\n </Text>\n )}\n\n <div\n onClick={() => !disabled && setIsModalOpen(true)}\n className={cn(\n \"flex items-center gap-3 px-3 py-2 border rounded-lg cursor-pointer transition-colors\",\n \"hover:border-border-strong bg-surface\",\n error ? \"border-danger-border\" : \"border-border\",\n disabled && \"opacity-50 cursor-not-allowed bg-surface-sunk\"\n )}\n >\n <div className=\"flex-shrink-0\">\n <Icon icon={selectedPointer ? FileText : HardDrive} color={selectedPointer ? \"primary\" : \"secondary\"} />\n </div>\n\n <div className=\"flex-grow truncate\">\n {selectedPointer ? (\n <span className=\"text-sm text-text font-medium\">{selectedPointer.name}</span>\n ) : (\n <span className=\"text-sm text-text-muted\">{placeholder}</span>\n )}\n </div>\n\n {selectedPointer && !disabled && (\n <button\n onClick={handleClear}\n className=\"p-1 hover:bg-surface-hover rounded\"\n >\n <Icon icon={X} size=\"xs\" />\n </button>\n )}\n </div>\n\n {error && (\n <Text variant=\"body\" size=\"xs\" className=\"text-danger-fg\">\n {error}\n </Text>\n )}\n\n <Modal\n open={isModalOpen}\n onClose={() => {\n setIsModalOpen(false);\n setSelectedMount(null);\n setCurrentPath(\"/\");\n setIsCreatingFolder(false);\n }}\n title={selectedMount ? `Explorer: ${selectedMount.name}` : \"Select Storage Mount\"}\n size=\"lg\"\n >\n <Tabs\n variant=\"pills\"\n items={[\n {\n id: 'remote',\n label: 'Platform Storage',\n content: (\n <div className=\"space-y-4\">\n {selectedMount ? (\n <>\n <div className=\"flex flex-wrap items-center gap-2\">\n <Button\n variant=\"ghost\"\n onClick={() => {\n if (currentPath && currentPath !== \"/\") {\n handleGoBack();\n } else {\n setSelectedMount(null);\n }\n }}\n leftIcon={<Icon icon={ArrowLeft} size=\"xs\" />}\n >\n {currentPath ? \"Back\" : \"Back to Mounts\"}\n </Button>\n\n <div className=\"flex items-center gap-1 text-xs text-text-muted overflow-hidden bg-surface-hover px-2 py-1 rounded\">\n <span className=\"truncate\">{currentPath}</span>\n </div>\n\n <div className=\"flex-grow min-w-40\">\n <TextField\n placeholder=\"Search...\"\n value={searchTerm}\n onChange={(e) => setSearchTerm(e.target.value)}\n startIcon={<Search size={14} />}\n fullWidth\n />\n </div>\n\n <div className=\"flex items-center gap-1\">\n <Button\n variant=\"outline\"\n onClick={() => setIsCreatingFolder(true)}\n leftIcon={<Icon icon={FolderPlus} size=\"xs\" />}\n >\n New Folder\n </Button>\n <Button\n variant=\"primary\"\n onClick={() => fileInputRef.current?.click()}\n leftIcon={<Icon icon={Upload} size=\"xs\" />}\n loading={loading}\n >\n Upload\n </Button>\n <input\n type=\"file\"\n className=\"hidden\"\n ref={fileInputRef}\n onChange={handleUploadToStorage}\n accept={accept}\n />\n </div>\n </div>\n\n {isCreatingFolder && (\n <div className=\"flex items-center gap-2 p-3 bg-surface-sunk rounded-lg border border-border\">\n <Icon icon={Folder} size=\"sm\" color=\"warning\" />\n <TextField\n placeholder=\"Folder name\"\n value={newFolderName}\n onChange={(e) => setNewFolderName(e.target.value)}\n autoFocus\n />\n <Button onClick={handleCreateFolder} loading={loading}>Create</Button>\n <Button variant=\"ghost\" onClick={() => setIsCreatingFolder(false)}>Cancel</Button>\n </div>\n )}\n\n <div className=\"max-h-100 overflow-auto rounded-lg border border-border\">\n <Table\n data={tableData}\n columns={explorerColumns}\n loading={loading}\n emptyContent=\"This folder is empty\"\n onRowClick={(row) => row.type === 'folder' ? handleFolderClick(row.name) : handleSelectRemote(row)}\n />\n </div>\n </>\n ) : (\n <div className=\"max-h-100 overflow-auto rounded-lg border border-border\">\n <Table\n data={mounts}\n columns={mountColumns}\n loading={loading}\n emptyContent=\"No storage mounts configured\"\n onRowClick={(row) => setSelectedMount(row)}\n />\n </div>\n )}\n </div>\n )\n },\n {\n id: 'local',\n label: 'Local File',\n content: (\n <div className=\"space-y-6\">\n <div className=\"flex flex-col items-center justify-center py-12 border-2 border-dashed border-border rounded-xl bg-surface-sunk/50\">\n <div className=\"p-4 bg-accent-soft rounded-full mb-4\">\n <Icon icon={FileText} size=\"xl\" color=\"primary\" />\n </div>\n <Text variant=\"label\" size=\"lg\" weight=\"semibold\">\n Select a file from your computer\n </Text>\n <Text variant=\"body\" size=\"sm\" className=\"text-text-muted mt-1 mb-6 text-center max-w-xs\">\n This file will be used directly in the form and will <strong>not</strong> be uploaded to platform storage.\n </Text>\n\n <label className=\"cursor-pointer\">\n <Button variant=\"primary\" size=\"lg\" loading={loading} className=\"pointer-events-none\">\n Browse Local File\n </Button>\n <input\n type=\"file\"\n className=\"hidden\"\n onChange={handleLocalOnlySelection}\n accept={accept}\n disabled={loading}\n />\n </label>\n </div>\n </div>\n )\n }\n ]}\n />\n </Modal>\n </div>\n );\n};\n","import React, { forwardRef } from 'react';\nimport { cn } from '../utils/cn';\nimport { fieldEdgeClasses, fieldFrameClasses, fieldLabelClasses } from './TextField';\n\nexport interface TextAreaProps extends Omit<React.TextareaHTMLAttributes<HTMLTextAreaElement>, 'size'> {\n /**\n * The label for the textarea field\n */\n label?: string;\n\n /**\n * Helper text to display below the textarea\n */\n helperText?: string;\n\n /**\n * Error message to display when the textarea is invalid\n */\n error?: string;\n\n /**\n * The size of the textarea field\n */\n size?: 'sm' | 'md' | 'lg' | 'full';\n\n /**\n * Whether the textarea should take the full width of its container\n */\n fullWidth?: boolean;\n\n /**\n * Whether the textarea is in a loading state\n */\n loading?: boolean;\n\n /**\n * Additional class name for the container\n */\n containerClassName?: string;\n\n /**\n * Additional class name for the label\n */\n labelClassName?: string;\n}\n\nconst textareaSizes = {\n sm: 'px-3 py-1.5 text-sm',\n md: 'px-3 py-2 text-base',\n lg: 'px-3 py-2 text-md',\n full: 'px-3 py-2 text-md',\n};\n\n/**\n * TextArea component with theme integration and validation states\n */\nexport const TextArea = forwardRef<HTMLTextAreaElement, TextAreaProps>(\n (\n {\n label,\n helperText,\n error,\n size = 'md',\n fullWidth = false,\n loading = false,\n containerClassName,\n labelClassName,\n className,\n id,\n rows = 4,\n ...props\n },\n ref\n ) => {\n const reactId = React.useId();\n const textareaId = id || `textarea-${reactId}`;\n const hasError = Boolean(error);\n const describedBy = error || helperText ? `${textareaId}-description` : undefined;\n\n return (\n <div className={cn('flex flex-col', fullWidth && 'w-full', containerClassName)}>\n {label && (\n <label\n htmlFor={textareaId}\n className={cn(\n fieldLabelClasses,\n hasError ? 'text-danger-fg' : 'text-text-muted',\n labelClassName\n )}\n >\n {label}\n </label>\n )}\n\n <div className=\"relative\">\n <textarea\n ref={ref}\n id={textareaId}\n rows={rows}\n aria-invalid={hasError || undefined}\n aria-describedby={describedBy}\n className={cn(\n fieldFrameClasses,\n 'resize-y leading-relaxed',\n\n textareaSizes[size],\n\n fieldEdgeClasses(hasError),\n\n className\n )}\n {...props}\n />\n\n {loading && (\n <span\n aria-hidden\n className=\"absolute top-2 right-3 size-icon-md animate-spin rounded-full border-2 border-border border-t-transparent\"\n />\n )}\n </div>\n\n {(error || helperText) && (\n <p\n id={describedBy}\n className={cn('mt-1 text-xs', hasError ? 'text-danger-fg' : 'text-text-subtle')}\n >\n {error || helperText}\n </p>\n )}\n </div>\n );\n }\n);\n\nTextArea.displayName = 'TextArea';\n","/**\n * Keeping password managers out of fields that are not credentials.\n *\n * The problem was not that autofill was switched on — it was that most fields\n * asked for it by accident. A form field passed things like `\"sip-password\"`,\n * `\"api-key\"`, `\"record-pin\"` or `\"system-prompt\"` as its autocomplete value.\n * None of those are autocomplete tokens, and the HTML spec says an unrecognised\n * token behaves as `on`. So the fields most likely to be mistaken for a login\n * were the ones most loudly inviting Bitwarden, LastPass and Dashlane to fill\n * them in — and to offer to save them.\n *\n * `autocomplete=\"off\"` alone does not settle it: the major managers ignore it on\n * purpose, because sites used to abuse it. Each honours its own opt-out\n * attribute instead, so a field that means it has to say so in four dialects.\n */\n\n/**\n * The autocomplete tokens we actually want honoured. Anything outside this set\n * is treated as \"someone wrote a note to themselves in this field\", not as a\n * browser instruction.\n */\nconst REAL_TOKENS = new Set([\n \"name\", \"given-name\", \"family-name\", \"additional-name\", \"nickname\",\n \"honorific-prefix\", \"honorific-suffix\",\n \"email\", \"username\", \"organization\", \"organization-title\",\n \"tel\", \"tel-country-code\", \"tel-national\", \"tel-extension\",\n \"url\", \"photo\", \"language\", \"bday\", \"sex\",\n \"street-address\", \"address-line1\", \"address-line2\", \"address-line3\",\n \"address-level1\", \"address-level2\", \"country\", \"country-name\", \"postal-code\",\n \"current-password\", \"new-password\", \"one-time-code\",\n]);\n\nexport interface AutofillProps {\n autoComplete: string;\n \"data-1p-ignore\"?: string;\n \"data-lpignore\"?: string;\n \"data-bwignore\"?: string;\n \"data-form-type\"?: string;\n}\n\n/**\n * Props that switch a field's autofill behaviour on or off deliberately.\n *\n * Pass the field's declared autocomplete value; a genuine token is honoured, and\n * anything else — including nothing at all — turns autofill off and tells each\n * manager so in the attribute it listens to.\n */\nexport function autofillProps(token?: string): AutofillProps {\n if (token && REAL_TOKENS.has(token)) return { autoComplete: token };\n\n return {\n autoComplete: \"off\",\n // 1Password\n \"data-1p-ignore\": \"true\",\n // LastPass\n \"data-lpignore\": \"true\",\n // Bitwarden\n \"data-bwignore\": \"true\",\n // Dashlane — \"other\" means \"not a login field\".\n \"data-form-type\": \"other\",\n };\n}\n","import { FilePointer, InternalSDK, VirtualMount } from \"@opencxh/domain\";\nimport { Plus, Trash2 } from \"lucide-react\";\nimport React, { useCallback, useEffect, useState } from \"react\";\nimport { Button } from \"../action/Button\";\nimport { SegmentedToggle } from \"../action/SegmentedToggle\";\nimport { Checkbox } from \"../input/Checkbox\";\nimport { DatePicker } from \"../input/DatePicker\";\nimport { FolderSelect, type FolderDestination } from \"../input/FolderSelect\";\nimport { Select } from \"../input/Select\";\nimport { StorageInput } from \"../input/StorageInput\";\nimport { TextArea } from \"../input/TextArea\";\nimport { TextField } from \"../input/TextField\";\nimport { cn } from \"../utils/cn\";\nimport { autofillProps } from \"./autofill\";\n\nexport type FormFieldType =\n | \"text\"\n | \"email\"\n | \"password\"\n | \"number\"\n | \"tel\"\n | \"url\"\n // A colour swatch. Its own type rather than `fieldProps: { type: \"color\" }`,\n // because the `type` prop is applied after the spread and would win.\n | \"color\"\n | \"textarea\"\n | \"select\"\n | \"segmented\"\n | \"checkbox\"\n | \"radio\"\n | \"date\"\n | \"file\"\n | \"folder\"\n | \"custom\"\n | \"array\";\n\n/**\n * `NonNullable` before the `object` test is load-bearing: form data is routinely\n * a `Partial<T>`, which makes every property `X | undefined`, and\n * `Address | undefined extends object` is false -- so without it every nested\n * path silently disappears and only top-level keys survive.\n *\n * Arrays, Dates and functions are treated as leaves. Recursing into them would\n * spell out every index and prototype method, and the resulting union is exactly\n * the kind of size at which TypeScript gives up (see {@link FieldPath}).\n *\n * `T extends unknown ?` makes this distribute over unions. Without it a\n * discriminated union like `OwnerScope` only contributes the keys its members\n * share (`keyof (A | B)` is an intersection), so `ownerScope.teamId` is\n * unspellable even though a `kind: \"team\"` conditional field needs exactly that.\n */\ntype NestedKeys<T> = T extends unknown\n ? {\n [K in keyof T]-?: NonNullable<T[K]> extends\n | readonly unknown[]\n | Date\n | ((...args: never[]) => unknown)\n ? K & string\n : NonNullable<T[K]> extends object\n ? `${K & string}.${NestedKeys<NonNullable<T[K]>>}`\n : K & string;\n }[keyof T]\n : never;\n\n/**\n * What a field may be named: any leaf path, plus any top-level key.\n *\n * The second half matters for `type: \"custom\"` fields, which own a whole\n * sub-object -- a discriminated union, a repeatable list -- and would otherwise\n * be unspellable, since `NestedKeys` only reaches leaves. It is added as a\n * separate union rather than folded into `NestedKeys` itself: doing it inside\n * the recursion doubles the union at every level, and TypeScript quietly gives\n * up on inferring `group.items` once it gets large enough.\n */\ntype FieldPath<T> = NestedKeys<T> | (keyof T & string);\n\nfunction getValueByPath<T>(obj: T, path: string): unknown {\n return path\n .split(\".\")\n .reduce(\n (acc, key) =>\n acc && typeof acc === \"object\" && key in acc\n ? (acc as any)[key]\n : undefined,\n obj\n );\n}\n\nfunction setValueByPath<T extends object>(obj: T, path: string, value: any): T {\n const keys = path.split(\".\");\n const clone: any = Array.isArray(obj)\n ? [...(obj as any)]\n : { ...(obj as any) };\n let cur: any = clone;\n\n for (let i = 0; i < keys.length - 1; i++) {\n const k = keys[i];\n const prev = cur[k];\n cur[k] =\n prev && typeof prev === \"object\"\n ? Array.isArray(prev)\n ? [...prev]\n : { ...prev }\n : {};\n cur = cur[k];\n }\n cur[keys[keys.length - 1]] = value;\n return clone;\n}\n\nfunction unsetByPath<T extends object>(obj: T, path: string): T {\n const keys = path.split(\".\");\n const clone: any = Array.isArray(obj)\n ? [...(obj as any)]\n : { ...(obj as any) };\n let cur: any = clone;\n\n for (let i = 0; i < keys.length - 1; i++) {\n const k = keys[i];\n if (!cur[k] || typeof cur[k] !== \"object\") return clone; // niets te doen\n cur[k] = Array.isArray(cur[k]) ? [...cur[k]] : { ...cur[k] };\n cur = cur[k];\n }\n delete cur[keys[keys.length - 1]];\n return clone;\n}\n\n/**\n * One band of a page-wide form: a fixed label column with the section title and\n * its explanation, and the fields beside it.\n *\n * Exported because a page often has a section that is not a `Form` field at all\n * — a checklist, a list of linked records — and it has to line up with the bands\n * above it. Without this those sections each re-derive the column width and the\n * spacing, and they drift.\n */\nexport function FormSection({\n title,\n description,\n className,\n children,\n}: {\n title?: string;\n description?: string;\n /** Caller owns the divider: only it knows whether it is the last band. */\n className?: string;\n children: React.ReactNode;\n}) {\n return (\n <div className={cn(\"flex flex-col gap-4 py-6 sm:flex-row sm:gap-8\", className)}>\n <div className=\"w-full shrink-0 sm:w-form-label\">\n {title && <span className=\"text-base font-semibold text-text\">{title}</span>}\n {description && (\n <p className=\"mt-1 text-sm leading-relaxed text-pretty text-text-subtle\">\n {description}\n </p>\n )}\n </div>\n <div className=\"min-w-0 flex-1\">{children}</div>\n </div>\n );\n}\n\nexport interface FormGroupItem<T = any> {\n /** Field name (key in form data) */\n name: FieldPath<T>;\n /** Field label */\n label: string;\n /** Field type */\n type: FormFieldType;\n /** Text input type (when type is 'text') */\n textType?: \"text\" | \"email\" | \"password\" | \"number\" | \"tel\" | \"url\";\n /** Field width (CSS width value or grid columns) */\n width?: string | number;\n /** Placeholder text */\n placeholder?: string;\n /**\n * Visible rows for `textarea`. Defaults to 4, which is right for a note and\n * far too small for a field that holds an instruction someone actually reads\n * back while editing (a system prompt).\n */\n rows?: number;\n /**\n * Autocomplete token. Only real HTML tokens (`email`, `tel`, `name`, …) are\n * passed to the browser; anything else switches autofill *off* rather than\n * silently meaning \"on\" — see {@link autofillProps}.\n */\n autocomplete?: string;\n /** Options for select/radio/checkbox types */\n options?: Array<{\n value: string | number;\n label: string;\n disabled?: boolean;\n }>;\n /** Validation function */\n validator?: (value: any, formData: T) => string | null;\n /** Conditional function to show/hide field */\n conditional?: (formData: T) => boolean;\n /** Whether field can be empty */\n allowEmpty?: boolean;\n /** Remove field from form data when empty */\n removeIfEmpty?: boolean;\n /**\n * Uitleg onder het veld: waarom bestaat dit veld, of wat is de consequentie van de\n * keuze. Voor velden waar het label de vraag niet volledig kan stellen — een\n * groep-`description` is te grof zodra een groep meerdere velden heeft.\n */\n help?: string;\n /** Whether field is hidden */\n hidden?: boolean;\n /** Whether field is required */\n required?: boolean;\n /** Whether field is disabled */\n disabled?: boolean;\n /** Custom component renderer */\n customComponent?: (props: {\n value: any;\n onChange: (value: any) => void;\n error?: string;\n disabled?: boolean;\n }) => React.ReactNode;\n /** Additional props to pass to the field component */\n fieldProps?: Record<string, any>;\n\n /** For 'array' type, defines the fields for each item in the array */\n arrayFields?: FormGroupItem<any>[];\n\n /** For 'select' type, whether the select should be searchable */\n searchable?: boolean;\n\n /** For 'select' type, whether the select should be multiple */\n multiple?: boolean;\n\n allowCreate?: boolean;\n\n // todo: add support for array of objects\n}\n\nexport interface FormGroup<T = any> {\n /** Group identifier */\n id: string;\n /**\n * Group title. Optional: a form that is one unbroken block of fields has no\n * heading to give, and the label column already renders empty when it is\n * absent — the type was simply stricter than the component.\n */\n title?: string;\n /** Group description */\n description?: string;\n /** Group items */\n items: FormGroupItem<T>[];\n /** Conditional function to show/hide group */\n conditional?: (formData: T) => boolean;\n /** Group layout */\n layout?: \"grid\" | \"flex\";\n /** Number of columns for grid layout */\n columns?: number;\n /** Additional CSS classes */\n className?: string;\n}\n\nexport interface FormButtonProps {\n /** Button label */\n label: string;\n /** Button variant */\n variant?: \"primary\" | \"secondary\" | \"outline\" | \"ghost\" | \"destructive\";\n /** Button size */\n size?: \"sm\" | \"md\" | \"lg\";\n /** Whether button is disabled */\n disabled?: boolean;\n /** Additional CSS classes */\n className?: string;\n}\n\nexport interface FormProps<T = Record<string, any>> {\n /** Form groups */\n groups: FormGroup<T>[];\n /** Initial form data */\n data?: Partial<T>;\n /** Form submit handler */\n onSubmit?: (data: T, transformedData?: any) => void | Promise<void>;\n /** Form cancel handler */\n onCancel?: () => void;\n /** Form change handler */\n onChange?: (data: Partial<T>, changedField?: keyof T) => void;\n /** Data transformation function (called before submit) */\n transform?: (data: T) => any;\n /** Form validation function */\n validate?: (data: T) => Record<keyof T, string> | null;\n /** Submit button props */\n submitButton?: FormButtonProps;\n /** Cancel button props */\n cancelButton?: FormButtonProps;\n /** Whether to show buttons */\n showButtons?: boolean;\n /** Form layout */\n layout?: \"vertical\" | \"horizontal\";\n /** Form size */\n size?: \"sm\" | \"md\" | \"lg\" | \"full\";\n /** Whether form is loading */\n loading?: boolean;\n /** Additional CSS classes */\n className?: string;\n /**\n * Form ref. Includes `| null` because that is what React 19's\n * `useRef<HTMLFormElement>(null)` produces; without it every caller has to\n * cast at the call site.\n */\n ref?: React.RefObject<HTMLFormElement | null>;\n /** SDK instance */\n sdk?: InternalSDK<any>;\n}\n\n/**\n * Generic Form component with groups, validation, and conditional rendering\n */\nexport const Form = <T extends Record<string, any>>({\n groups,\n data: externalData,\n onSubmit,\n onCancel,\n onChange,\n transform,\n validate,\n submitButton = { label: \"Submit\", variant: \"primary\" },\n cancelButton = { label: \"Cancel\", variant: \"outline\" },\n showButtons = true,\n layout = \"vertical\",\n size = \"md\",\n loading = false,\n className,\n ref,\n sdk,\n}: FormProps<T>) => {\n const [formData, setFormData] = useState<Partial<T>>(externalData || {});\n const [errors, setErrors] = useState<Record<string, string>>({});\n const [touched, setTouched] = useState<Record<string, boolean>>({});\n\n // Update internal data when external data changes\n useEffect(() => {\n if (externalData) {\n setFormData({ ...externalData });\n }\n }, [externalData]);\n\n // Validate a single field\n const validateField = useCallback(\n (name: keyof T, value: any, currentData: Partial<T>) => {\n const field = groups\n .flatMap((group) => group.items)\n .find((item) => item.name === name);\n\n if (!field) return null;\n\n // Required validation\n if (\n field.required &&\n (value === undefined || value === null || value === \"\")\n ) {\n return `${field.label} is required`;\n }\n\n if (field.type === \"array\") {\n if (field.required && (!value || value.length === 0)) {\n return `${field.label} cannot be empty.`;\n }\n if (value && !Array.isArray(value)) {\n return `${field.label} must be an array.`;\n }\n\n if (Array.isArray(value) && field.arrayFields) {\n const arrayErrors: Record<string, any>[] = [];\n let hasErrors = false;\n value.forEach((row, index) => {\n const rowErrors: Record<string, string> = {};\n for (const subField of field.arrayFields!) {\n const subFieldValue = row?.[subField.name];\n if (\n subField.required &&\n (subFieldValue === undefined ||\n subFieldValue === null ||\n subFieldValue === \"\")\n ) {\n rowErrors[\n subField.name as string\n ] = `${subField.label} is required`;\n hasErrors = true;\n } else if (subField.validator) {\n const error = subField.validator(subFieldValue, row);\n if (error) {\n rowErrors[subField.name as string] = error;\n hasErrors = true;\n }\n }\n }\n arrayErrors[index] = rowErrors;\n });\n\n if (hasErrors) {\n return JSON.stringify(arrayErrors);\n }\n }\n }\n\n // Custom validation\n if (field.validator) {\n return field.validator(value, currentData as T);\n }\n\n return null;\n },\n [groups]\n );\n\n // Handle field change\n const handleFieldChange = useCallback(\n (name: keyof T, value: any) => {\n let newData = setValueByPath(\n formData as object,\n name as string,\n value\n ) as Partial<T>;\n\n // Handle removeIfEmpty\n const field = groups.flatMap((g) => g.items).find((i) => i.name === name);\n if (\n field?.removeIfEmpty &&\n (value === undefined || value === null || value === \"\")\n ) {\n newData = unsetByPath(newData as object, name as string) as Partial<T>;\n }\n\n setFormData(newData);\n setTouched((prev) => ({ ...prev, [name]: true }));\n\n // Validate field\n const error = validateField(name, value, newData);\n setErrors((prev) => ({\n ...prev,\n [name]: error || \"\",\n }));\n\n // Call onChange callback\n onChange?.(newData, name);\n },\n [formData, groups, validateField, onChange]\n );\n\n // Handle form submission\n const handleSubmit = useCallback(\n async (e: React.FormEvent) => {\n e.preventDefault();\n\n if (loading) return;\n\n // Validate all fields\n const newErrors: Record<string, string> = {};\n const allFields = groups.flatMap((group) => group.items);\n\n for (const field of allFields) {\n // Skip hidden or conditional fields\n if (\n field.hidden ||\n (field.conditional && !field.conditional(formData as T))\n ) {\n continue;\n }\n\n const error = validateField(\n field.name,\n getValueByPath<Partial<T>>(formData, field.name),\n formData\n );\n if (error) {\n newErrors[field.name as string] = error;\n }\n }\n\n // Run form-level validation\n if (validate) {\n const formErrors = validate(formData as T);\n if (formErrors) {\n Object.assign(newErrors, formErrors);\n }\n }\n\n setErrors(newErrors);\n\n // If there are errors, don't submit\n if (Object.keys(newErrors).some((key) => newErrors[key])) {\n return;\n }\n\n // Transform data if needed\n const finalData = transform ? transform(formData as T) : formData;\n\n // Submit form\n await onSubmit?.(formData as T, finalData);\n },\n [formData, groups, validateField, validate, transform, onSubmit, loading]\n );\n\n // Render field based on type\n const renderField = useCallback(\n (item: FormGroupItem<T>) => {\n const value = getValueByPath<Partial<T>>(formData, item.name) as\n | string\n | undefined;\n const error = touched[item.name as string]\n ? errors[item.name as string]\n : undefined;\n const isDisabled = item.disabled || loading;\n\n const commonProps = {\n value: value || \"\",\n disabled: isDisabled,\n required: item.required,\n placeholder: item.placeholder,\n ...item.fieldProps,\n };\n\n switch (item.type) {\n case \"text\":\n case \"email\":\n case \"password\":\n case \"number\":\n case \"tel\":\n case \"url\":\n case \"color\":\n return (\n <TextField\n {...commonProps}\n onChange={(e) => handleFieldChange(item.name, e.target.value)}\n type={item.textType || item.type}\n {...autofillProps(item.autocomplete)}\n error={error}\n size={size}\n />\n );\n\n case \"textarea\":\n return (\n <TextArea\n {...commonProps}\n onChange={(e) => handleFieldChange(item.name, e.target.value)}\n rows={item.rows ?? 4}\n error={error}\n size={size}\n />\n );\n\n case \"select\":\n return (\n <Select\n {...commonProps}\n onChange={(e) => handleFieldChange(item.name, e)}\n options={(item.options || []).map((option) => ({\n ...option,\n value: String(option.value),\n }))}\n searchable={item.searchable}\n multiple={item.multiple}\n allowCreate={item.allowCreate}\n error={error}\n size={size}\n />\n );\n\n // A short, fixed set of mutually exclusive values — priority, a scope,\n // a status. All options visible at once beats a dropdown you have to\n // open to learn what the choices even are.\n case \"segmented\":\n return (\n <SegmentedToggle\n aria-label={item.label}\n value={value == null ? \"\" : String(value)}\n onChange={(next) => handleFieldChange(item.name, next)}\n options={(item.options || []).map((option) => ({\n value: String(option.value),\n label: option.label,\n }))}\n size={size === \"sm\" ? \"sm\" : \"md\"}\n className={item.disabled ? \"pointer-events-none opacity-50\" : undefined}\n />\n );\n\n case \"checkbox\":\n return (\n <Checkbox\n {...commonProps}\n label={item.label}\n checked={Boolean(value)}\n onChange={(e) => handleFieldChange(item.name, e.target.checked)}\n size={size}\n />\n );\n\n case \"radio\":\n return (\n <div className=\"flex flex-col gap-2\">\n {item.options?.map((option) => (\n <label\n key={option.value}\n // gap-3 like Checkbox: a radio row and a checkbox row in the\n // same form must sit the same distance from their label.\n className=\"flex cursor-pointer items-center gap-3 text-base text-text\"\n >\n <input\n type=\"radio\"\n name={item.name as string}\n value={option.value}\n checked={value === option.value}\n onChange={() => handleFieldChange(item.name, option.value)}\n disabled={isDisabled || option.disabled}\n className=\"size-checkbox shrink-0 rounded-xs border border-border-strong bg-surface-input accent-accent focus-visible:outline-none focus-visible:focus-ring\"\n />\n {option.label}\n </label>\n ))}\n </div>\n );\n\n case \"date\":\n return (\n <DatePicker\n {...commonProps}\n value={value ? new Date(value) : null}\n onChange={(date) => handleFieldChange(item.name, date)}\n size={size}\n />\n );\n\n case \"file\":\n return (\n <StorageInput\n {...commonProps}\n value={value}\n onChange={(pointer) => handleFieldChange(item.name, pointer)}\n error={error}\n onListFiles={(filters) => sdk?.http.invoke<{ data: FilePointer[] }>({\n method: \"POST\",\n action: \"storage.file.list\",\n body: filters,\n })}\n onListMounts={() => sdk?.http.invoke<{ data: VirtualMount[] }>({\n method: \"GET\",\n action: \"storage.mount\",\n })}\n onUploadFile={(payload) => sdk?.http.invoke<{ data: FilePointer }>({\n method: \"POST\",\n action: \"storage.file.upload\",\n body: payload,\n })}\n onDownloadFile={(fileId) => sdk?.http.invoke<Uint8Array>({\n method: \"GET\",\n action: `storage.file.${fileId}.download`,\n })}\n onRegisterFile={(payload) => sdk?.http.invoke<{ data: FilePointer }>({\n method: \"POST\",\n action: \"storage.file.folder\",\n body: payload,\n })}\n />\n );\n\n case \"folder\":\n return (\n <FolderSelect\n value={(value as unknown as FolderDestination) || {}}\n onChange={(v) => handleFieldChange(item.name, v)}\n onListFolders={() => sdk?.http.invoke<{ data: VirtualMount[] }>({\n method: \"GET\",\n action: \"storage.mount\",\n })}\n disabled={isDisabled}\n size={size}\n placeholder={item.placeholder}\n />\n );\n\n case \"custom\":\n return item.customComponent?.({\n value,\n onChange: (newValue) => handleFieldChange(item.name, newValue),\n error,\n disabled: isDisabled,\n });\n\n case \"array\": {\n const arrayValue = (value || []) as any[];\n let arrayErrors: Record<string, string>[] = [];\n if (typeof error === \"string\" && error.startsWith(\"[\")) {\n try {\n arrayErrors = JSON.parse(error);\n } catch (e) {\n // ignore parse error\n }\n }\n\n const handleAddItem = () => {\n handleFieldChange(item.name, [...arrayValue, {}]);\n };\n\n const handleRemoveItem = (index: number) => {\n handleFieldChange(\n item.name,\n arrayValue.filter((_, i) => i !== index)\n );\n };\n\n const handleSubFieldChange = (\n index: number,\n fieldName: string,\n fieldValue: any\n ) => {\n const newArray = [...arrayValue];\n newArray[index] = {\n ...newArray[index],\n [fieldName]: fieldValue,\n };\n handleFieldChange(item.name, newArray);\n };\n\n return (\n <div className=\"flex flex-col gap-2\">\n {arrayValue.map((row, index) => (\n <div key={index} className=\"flex items-start gap-2\">\n <div className=\"grid flex-1 gap-2 sm:grid-cols-2\">\n {item.arrayFields?.map((subField) => {\n const subFieldError =\n arrayErrors?.[index]?.[subField.name as string];\n return (\n <div\n key={subField.name as string}\n className=\"flex flex-col gap-1\"\n >\n {index === 0 && (\n <label className=\"block text-xs font-semibold uppercase tracking-label text-text-subtle\">\n {subField.label}\n {subField.required && (\n <span className=\"ml-1 text-danger-fg\">*</span>\n )}\n </label>\n )}\n {/* Note: Duplicating field rendering logic here. Could be refactored. */}\n {(() => {\n const commonSubFieldProps = {\n value: row?.[subField.name] || \"\",\n disabled: isDisabled,\n required: subField.required,\n placeholder: subField.placeholder,\n ...subField.fieldProps,\n };\n switch (subField.type) {\n case \"text\":\n case \"email\":\n case \"password\":\n case \"number\":\n case \"tel\":\n case \"url\":\n return (\n <TextField\n {...commonSubFieldProps}\n onChange={(e) =>\n handleSubFieldChange(\n index,\n subField.name as string,\n e.target.value\n )\n }\n type={subField.textType || subField.type}\n {...autofillProps(subField.autocomplete)}\n error={subFieldError}\n size={size}\n />\n );\n case \"textarea\":\n return (\n <TextArea\n {...commonSubFieldProps}\n onChange={(e) =>\n handleSubFieldChange(\n index,\n subField.name as string,\n e.target.value\n )\n }\n rows={subField.rows ?? 4}\n error={subFieldError}\n size={size}\n />\n );\n case \"select\":\n return (\n <Select\n {...commonSubFieldProps}\n onChange={(e) =>\n handleSubFieldChange(\n index,\n subField.name as string,\n e\n )\n }\n options={(subField.options || []).map(\n (option) => ({\n ...option,\n value: String(option.value),\n })\n )}\n searchable={subField.searchable}\n multiple={subField.multiple}\n allowCreate={subField.allowCreate}\n error={subFieldError}\n size={size}\n />\n );\n case \"checkbox\":\n return (\n <Checkbox\n {...commonSubFieldProps}\n checked={Boolean(row?.[subField.name])}\n onChange={(e) =>\n handleSubFieldChange(\n index,\n subField.name as string,\n e.target.checked\n )\n }\n size={size}\n />\n );\n case \"radio\":\n return (\n <div className=\"flex flex-col gap-2\">\n {subField.options?.map((option) => (\n <label\n key={option.value}\n className=\"flex cursor-pointer items-center gap-2 text-base text-text\"\n >\n <input\n type=\"radio\"\n name={`${item.name as string\n }.${index}.${subField.name as string\n }`}\n value={option.value}\n checked={\n row?.[subField.name] ===\n option.value\n }\n onChange={() =>\n handleSubFieldChange(\n index,\n subField.name as string,\n option.value\n )\n }\n disabled={\n isDisabled || option.disabled\n }\n className=\"size-checkbox shrink-0 rounded-xs border border-border-strong bg-surface-input accent-accent focus-visible:outline-none focus-visible:focus-ring\"\n />\n {option.label}\n </label>\n ))}\n </div>\n );\n case \"date\": {\n const dateValue = row?.[subField.name];\n return (\n <DatePicker\n {...commonSubFieldProps}\n value={\n dateValue ? new Date(dateValue) : null\n }\n onChange={(date) =>\n handleSubFieldChange(\n index,\n subField.name as string,\n date\n )\n }\n size={size}\n />\n );\n }\n case \"custom\":\n return subField.customComponent?.({\n value: row?.[subField.name],\n onChange: (newValue) =>\n handleSubFieldChange(\n index,\n subField.name as string,\n newValue\n ),\n error: subFieldError,\n disabled: isDisabled,\n });\n // Add other field types here as needed\n default:\n return (\n <p>\n Unsupported field type in array:{\" \"}\n {subField.type}\n </p>\n );\n }\n })()}\n {subFieldError && (\n <p className=\"text-xs text-danger-fg\">{subFieldError}</p>\n )}\n </div>\n );\n })}\n </div>\n <Button\n type=\"button\"\n iconOnly\n variant=\"ghost\"\n size=\"md\"\n aria-label={`${item.label} verwijderen`}\n onClick={() => handleRemoveItem(index)}\n disabled={isDisabled}\n className={cn(\"shrink-0\", index === 0 && \"mt-5\")}\n >\n <Trash2 className=\"size-icon-md\" />\n </Button>\n </div>\n ))}\n <Button\n type=\"button\"\n variant=\"secondary\"\n leftIcon={<Plus className=\"size-icon-sm\" />}\n onClick={handleAddItem}\n disabled={isDisabled}\n >\n {item.label} toevoegen\n </Button>\n </div>\n );\n }\n\n default:\n return null;\n }\n },\n [formData, touched, errors, loading, size, handleFieldChange]\n );\n\n // Render form group\n const renderGroup = useCallback(\n (group: FormGroup<T>) => {\n // Check group conditional\n if (group.conditional && !group.conditional(formData as T)) {\n return null;\n }\n\n const visibleItems = group.items.filter((item) => {\n if (item.hidden) return false;\n if (item.conditional && !item.conditional(formData as T)) return false;\n return true;\n });\n\n if (visibleItems.length === 0) return null;\n\n const groupClasses = cn(\n group.layout === \"flex\" ? \"flex flex-wrap gap-3.5\" : \"grid gap-3.5\",\n group.layout !== \"flex\" && {\n \"grid-cols-1\": !group.columns || group.columns === 1,\n \"grid-cols-2\": group.columns === 2,\n \"grid-cols-3\": group.columns === 3,\n \"grid-cols-4\": group.columns === 4,\n },\n group.className\n );\n\n return (\n // A band across the page, closed off with a hairline — no card. The\n // form *is* the page now, so a panel around each section would be a\n // second surface on top of the one it already sits on.\n <FormSection\n key={group.id}\n title={group.title}\n description={group.description}\n className=\"not-last:border-b not-last:border-border-subtle\"\n >\n {/* Group Items */}\n <div>\n <div className={groupClasses}>\n {visibleItems.map((item) => {\n const fieldError = touched[item.name as string]\n ? errors[item.name as string]\n : undefined;\n\n return (\n <div\n key={item.name as string}\n className={cn(\n \"flex min-w-0 flex-col gap-1.5\",\n item.type === \"checkbox\" && \"justify-center\"\n )}\n style={{\n width: typeof item.width === \"string\" ? item.width : undefined,\n gridColumn:\n typeof item.width === \"number\"\n ? `span ${item.width} / span ${item.width}`\n : undefined,\n }}\n >\n {/* Field Label — checkbox carries its own label on the right */}\n {item.type !== \"custom\" && item.type !== \"checkbox\" && (\n <label className=\"block text-sm font-medium text-text-muted\">\n {item.label}\n {item.required && (\n <span className=\"ml-1 text-danger-fg\">*</span>\n )}\n </label>\n )}\n\n {/* Field Input */}\n {renderField(item)}\n\n {/* Uitleg onder het veld (los van een validatiefout). */}\n {item.help && !fieldError && (\n <p className=\"text-xs leading-4 text-text-subtle\">{item.help}</p>\n )}\n </div>\n );\n })}\n </div>\n </div>\n </FormSection>\n );\n },\n [formData, touched, errors, renderField]\n );\n\n // No panel chrome: the page (or the card the page sits in) is the surface.\n // `size` is a reading width, nothing more — `md` is the standard form column.\n const formClasses = cn(\n {\n \"max-w-settings\": size === \"sm\",\n \"max-w-form\": size === \"md\",\n \"max-w-6xl\": size === \"lg\",\n \"max-w-full\": size === \"full\",\n },\n className\n );\n\n const buttonSize = size === \"full\" ? \"md\" : size;\n\n return (\n <form ref={ref} onSubmit={handleSubmit} className={formClasses}>\n {/* Implicit submission. A form with several fields and no submit button\n inside it ignores Enter entirely — which is what happens whenever the\n save button lives in a page header (showButtons={false}). This hidden\n button is the form's default button, so Enter in a text field submits\n the way it does everywhere else. */}\n {!showButtons && <button type=\"submit\" className=\"hidden\" tabIndex={-1} aria-hidden />}\n\n {/* Form Groups — bands down the page, separated by a hairline */}\n <div className=\"flex flex-col\">{groups.map(renderGroup)}</div>\n\n {/* Footer. Only when it has something in it: without the panel around the\n form, an empty footer is a rule hanging under the last section. */}\n {showButtons && (\n <div className=\"flex items-center gap-2 border-t border-border-subtle py-4\">\n <>\n <div className=\"ml-auto\" />\n {onCancel && (\n <Button\n type=\"button\"\n variant={cancelButton.variant ?? \"ghost\"}\n size={cancelButton.size || buttonSize}\n disabled={cancelButton.disabled || loading}\n onClick={onCancel}\n className={cancelButton.className}\n >\n {cancelButton.label}\n </Button>\n )}\n\n <Button\n type=\"submit\"\n variant={submitButton.variant}\n size={submitButton.size || buttonSize}\n disabled={submitButton.disabled || loading}\n loading={loading}\n className={submitButton.className}\n >\n {submitButton.label}\n </Button>\n </>\n </div>\n )}\n </form>\n );\n};\n","import React from \"react\";\nimport { Button } from \"../action/Button\";\nimport { Text } from \"../typography/Text\";\nimport { Modal } from \"./Modal\";\n\nexport interface ConfirmDialogProps {\n open: boolean;\n title: string;\n /** What is about to happen, and what it costs if it is wrong. */\n description?: React.ReactNode;\n confirmLabel?: string;\n cancelLabel?: string;\n /** `danger` for anything that destroys or detaches something. */\n tone?: \"default\" | \"danger\";\n /** Disables both buttons and puts the confirm button in its loading state. */\n loading?: boolean;\n onConfirm: () => void;\n onCancel: () => void;\n}\n\n/**\n * Confirmation before a destructive or irreversible action.\n *\n * Replaces `window.confirm`, which blocks the main thread, cannot be styled,\n * cannot be translated, and is suppressed outright in some embedded contexts.\n * Note the shape difference: `confirm()` returns a boolean inline, so callers\n * written as `if (!confirm(...)) return;` have to split into a request step\n * and a confirm step.\n *\n * @example\n * ```tsx\n * <ConfirmDialog\n * open={pendingDelete !== null}\n * tone=\"danger\"\n * title={t(\"channel_delete_title\")}\n * description={t(\"channel_delete_description\")}\n * confirmLabel={t(\"delete\")}\n * onConfirm={() => remove(pendingDelete!)}\n * onCancel={() => setPendingDelete(null)}\n * />\n * ```\n */\nexport function ConfirmDialog({\n open,\n title,\n description,\n confirmLabel = \"Bevestigen\",\n cancelLabel = \"Annuleren\",\n tone = \"default\",\n loading = false,\n onConfirm,\n onCancel,\n}: ConfirmDialogProps) {\n return (\n <Modal\n open={open}\n onClose={onCancel}\n title={title}\n size=\"sm\"\n footer={\n <div className=\"flex w-full items-center justify-end gap-2\">\n <Button variant=\"ghost\" onClick={onCancel} disabled={loading}>\n {cancelLabel}\n </Button>\n <Button\n variant={tone === \"danger\" ? \"destructive\" : \"primary\"}\n onClick={onConfirm}\n loading={loading}\n >\n {confirmLabel}\n </Button>\n </div>\n }\n >\n {description && <Text color=\"secondary\">{description}</Text>}\n </Modal>\n );\n}\n","import React from 'react';\nimport { X } from \"lucide-react\";\nimport { Icon } from \"../content/Icon\";\nimport { cn } from '../utils/cn';\n\n/**\n * `color` is deliberately omitted from the inherited HTML attributes. It is a\n * legacy HTML attribute, so `<Badge color=\"success\">` used to type-check while\n * doing nothing at all — the badge silently rendered as `default`. Omitting it\n * turns that mistake into a compile error pointing at `variant`.\n */\nexport interface BadgeProps extends Omit<React.HTMLAttributes<HTMLSpanElement>, 'color'> {\n /**\n * The visual variant of the badge\n */\n variant?: 'default' | 'primary' | 'secondary' | 'success' | 'warning' | 'error' | 'info' | 'note';\n \n /**\n * The size of the badge\n */\n size?: 'sm' | 'md' | 'lg';\n \n /**\n * Whether the badge should have a dot indicator\n */\n dot?: boolean;\n \n /**\n * Icon to display in the badge\n */\n icon?: React.ReactNode;\n \n /**\n * Whether the badge can be dismissed\n */\n dismissible?: boolean;\n \n /**\n * Callback fired when the badge is dismissed\n */\n onDismiss?: () => void;\n}\n\n// Semantic, token-driven (mode-aware via CSS custom properties — no dark: overrides needed)\nconst badgeVariants = {\n default: 'bg-surface-hover text-text',\n primary: 'bg-accent-soft text-accent',\n secondary: 'bg-surface-hover text-text-muted',\n success: 'bg-success-soft text-success-fg',\n warning: 'bg-warning-soft text-warning-fg',\n error: 'bg-danger-soft text-danger-fg',\n info: 'bg-info-soft text-info-fg',\n // Internal-note amber. Never for customer-visible content.\n note: 'bg-note-soft text-note',\n};\n\nconst badgeSizes = {\n sm: 'px-2 py-0.5 text-xs',\n md: 'px-2.5 py-1 text-sm',\n lg: 'px-3 py-1.5 text-base',\n};\n\nconst dotColors = {\n default: 'bg-surface-hover',\n primary: 'bg-accent',\n secondary: 'bg-surface-hover',\n success: 'bg-success',\n warning: 'bg-warning',\n error: 'bg-danger',\n info: 'bg-info',\n note: 'bg-note',\n};\n\n/**\n * Badge component for displaying status indicators and labels\n * \n * @example\n * ```tsx\n * <Badge variant=\"success\">Active</Badge>\n * \n * <Badge variant=\"warning\" dot>\n * Pending\n * </Badge>\n * \n * <Badge variant=\"error\" dismissible onDismiss={() => console.log('dismissed')}>\n * Error\n * </Badge>\n * \n * <Badge variant=\"primary\" icon={<StarIcon />}>\n * Featured\n * </Badge>\n * ```\n */\nexport function Badge({\n variant = 'default',\n size = 'md',\n dot = false,\n icon,\n dismissible = false,\n onDismiss,\n className,\n children,\n ...props\n}: BadgeProps) {\n return (\n <span\n className={cn(\n // Base styles\n 'inline-flex items-center font-medium rounded-full',\n \n // Variant styles\n badgeVariants[variant],\n \n // Size styles\n badgeSizes[size],\n \n className\n )}\n {...props}\n >\n {dot && (\n <span\n className={cn(\n 'w-2 h-2 rounded-full mr-1.5',\n dotColors[variant]\n )}\n />\n )}\n \n {icon && (\n <span className={cn('flex-shrink-0', children && 'mr-1')}>\n {icon}\n </span>\n )}\n \n {children}\n \n {dismissible && onDismiss && (\n <button\n onClick={onDismiss}\n className=\"ml-1.5 flex-shrink-0 hover:opacity-70 transition-opacity\"\n aria-label=\"Remove badge\"\n >\n <Icon icon={X} size=\"xs\" color=\"current\" />\n </button>\n )}\n </span>\n );\n} ","import { ReactNode } from 'react';\nimport { cn } from '../utils/cn';\n\n/**\n * What is about to appear here. A placeholder only does its job if it has the\n * geometry of the thing it stands in for: the default `text` shape under a form\n * or a list announces a heading and two paragraphs, and the real content then\n * shoves everything sideways when it lands.\n */\nexport type ContentLoadingShape =\n | \"text\"\n | \"table\"\n | \"list\"\n | \"form\"\n | \"menu\"\n | \"cards\";\n\nexport interface ContentLoadingProps {\n /**\n * `page` (default) fills the route with its own `<main>` shell and padding.\n * `inline` drops both, so the skeleton can sit inside an existing panel,\n * card or scroll container without nesting a second `<main>` landmark.\n */\n variant?: \"page\" | \"inline\";\n\n /** The shape of what is coming. Defaults to `text`. */\n shape?: ContentLoadingShape;\n\n /** Rows/items/fields/cards to draw, depending on `shape`. */\n rows?: number;\n\n /** Columns, for `table` and `cards`. */\n columns?: number;\n\n /**\n * Optional custom skeleton content (overrides default)\n */\n children?: ReactNode;\n\n className?: string;\n\n /** @deprecated Pass `shape=\"table\"`. */\n showTableSkeleton?: boolean;\n /** @deprecated Pass `columns`. */\n tableColumns?: number;\n /** @deprecated Pass `rows`. */\n tableRows?: number;\n}\n\n/** One placeholder bar. Uneven widths read as text rather than as a progress bar. */\nconst Bar = ({ className }: { className?: string }) => (\n <span className={cn(\"block rounded-xs bg-surface-hover\", className)} />\n);\n\nconst WIDTHS = [\"62%\", \"44%\", \"74%\", \"52%\", \"68%\", \"48%\", \"80%\", \"56%\"];\n\nfunction Shape({ shape, rows, columns }: { shape: ContentLoadingShape; rows: number; columns: number }) {\n switch (shape) {\n case \"table\":\n return (\n <div className=\"overflow-hidden rounded-lg ring-1 ring-border\">\n <div\n className=\"grid gap-2 bg-surface-hover p-3\"\n style={{ gridTemplateColumns: `repeat(${columns}, minmax(0, 1fr))` }}\n >\n {Array.from({ length: columns }).map((_, i) => (\n <Bar key={`h-${i}`} className=\"h-4 w-2/3 bg-border-strong\" />\n ))}\n </div>\n {Array.from({ length: rows }).map((_, r) => (\n <div\n key={`r-${r}`}\n className=\"grid gap-2 border-t border-border-subtle p-3\"\n style={{ gridTemplateColumns: `repeat(${columns}, minmax(0, 1fr))` }}\n >\n {Array.from({ length: columns }).map((_, c) => (\n <Bar key={`c-${r}-${c}`} className=\"h-4 w-full\" />\n ))}\n </div>\n ))}\n </div>\n );\n\n case \"list\":\n return (\n <div className=\"flex flex-col divide-y divide-border-subtle rounded-lg ring-1 ring-border\">\n {Array.from({ length: rows }).map((_, i) => (\n <div key={i} className=\"flex items-center gap-3 p-3\">\n <Bar className=\"size-avatar-sm shrink-0 rounded-full\" />\n <div className=\"flex min-w-0 flex-1 flex-col gap-1.5\">\n <Bar className=\"h-3\" />\n <Bar className=\"h-2.5 opacity-70\" />\n </div>\n </div>\n ))}\n </div>\n );\n\n case \"form\":\n // Label above, field below — the pair a form actually renders, so the\n // fields do not jump when they replace this.\n return (\n <div className=\"flex flex-col gap-5\">\n {Array.from({ length: rows }).map((_, i) => (\n <div key={i} className=\"flex flex-col gap-2\">\n <Bar className=\"h-2.5 w-28\" />\n <Bar className=\"h-control-md w-full rounded-md\" />\n </div>\n ))}\n </div>\n );\n\n case \"menu\":\n // The same geometry the sidebar menu draws: a caption, then rows at item\n // height with room for the icon.\n return (\n <div className=\"flex flex-col gap-px\">\n <div className=\"px-2.5 pb-2 pt-5\">\n <Bar className=\"h-2 w-16\" />\n </div>\n {Array.from({ length: rows }).map((_, i) => (\n <div key={i} className=\"flex h-row-md items-center gap-2.5 px-2.5\">\n <Bar className=\"size-4 shrink-0\" />\n <Bar className=\"h-2\" />\n </div>\n ))}\n </div>\n );\n\n case \"cards\":\n return (\n <div\n className=\"grid gap-4\"\n style={{ gridTemplateColumns: `repeat(${columns}, minmax(0, 1fr))` }}\n >\n {Array.from({ length: rows * columns }).map((_, i) => (\n <div key={i} className=\"flex flex-col gap-2 rounded-lg p-4 ring-1 ring-border\">\n <Bar className=\"h-3 w-1/2\" />\n <Bar className=\"h-2.5\" />\n <Bar className=\"h-2.5 w-3/4 opacity-70\" />\n </div>\n ))}\n </div>\n );\n\n case \"text\":\n default:\n return (\n <div className=\"flex flex-col gap-6\">\n <Bar className=\"h-6 w-1/4\" />\n <div className=\"flex flex-col gap-2\">\n {Array.from({ length: rows }).map((_, i) => (\n <Bar key={i} className=\"h-4\" />\n ))}\n </div>\n </div>\n );\n }\n}\n\n/** Sensible counts per shape, so a call site only names the shape. */\nconst DEFAULT_ROWS: Record<ContentLoadingShape, number> = {\n text: 2,\n table: 8,\n list: 6,\n form: 5,\n menu: 4,\n cards: 2,\n};\n\nexport function ContentLoading({\n variant = \"page\",\n shape,\n rows,\n columns,\n children,\n className,\n showTableSkeleton = false,\n tableColumns,\n tableRows,\n}: ContentLoadingProps) {\n // The deprecated table props still decide the shape when no `shape` is given,\n // so existing call sites keep rendering what they always did.\n const resolvedShape: ContentLoadingShape = shape ?? (showTableSkeleton ? \"table\" : \"text\");\n const resolvedRows = rows ?? tableRows ?? DEFAULT_ROWS[resolvedShape];\n const resolvedColumns = columns ?? tableColumns ?? (resolvedShape === \"cards\" ? 3 : 6);\n\n // `inline` renders the skeleton bare; `page` wraps it in the route shell.\n const inner = (\n <div className={cn(\"w-full animate-pulse\", className)} aria-hidden>\n {children ?? (\n <Shape shape={resolvedShape} rows={resolvedRows} columns={resolvedColumns} />\n )}\n </div>\n );\n\n if (variant === \"inline\") return inner;\n\n return <main className=\"flex-1 bg-surface p-6\">{inner}</main>;\n}\n","import React from \"react\";\nimport { cn } from \"../utils/cn\";\n\nexport interface EmptyStateProps extends Omit<React.HTMLAttributes<HTMLDivElement>, \"title\"> {\n /** Leading glyph or icon (e.g. a check for the focus \"queue empty\" state). */\n icon?: React.ReactNode;\n /** Tint of the icon disc. */\n tone?: \"neutral\" | \"success\";\n /** Headline. */\n title: React.ReactNode;\n /** Supporting copy. */\n description?: React.ReactNode;\n /** Action buttons row. */\n actions?: React.ReactNode;\n /** Render inside a raised card (focus \"done\" state) vs. plain centered block. */\n card?: boolean;\n}\n\nconst toneDisc: Record<NonNullable<EmptyStateProps[\"tone\"]>, string> = {\n neutral: \"bg-surface-hover text-text-muted\",\n success: \"bg-success-soft text-success-fg\",\n};\n\n/**\n * Centered empty / completion state (focus queue done, no-results lists).\n *\n * @example\n * ```tsx\n * <EmptyState card tone=\"success\" icon={<Icon icon={Check} size=\"lg\" />}\n * title=\"Wachtrij leeg — 7 afgehandeld\"\n * description=\"Nieuwe gesprekken verschijnen hier vanzelf.\"\n * actions={<Button>Terug naar Mijn dag</Button>} />\n * ```\n */\nexport function EmptyState({\n icon,\n tone = \"neutral\",\n title,\n description,\n actions,\n card = false,\n className,\n ...props\n}: EmptyStateProps) {\n return (\n <div\n className={cn(\n \"flex flex-col items-center gap-2.5 text-center\",\n card && \"rounded-lg border border-border bg-surface px-11 py-9 shadow-overlay\",\n className,\n )}\n {...props}\n >\n {icon != null && (\n <span className={cn(\"flex size-disc items-center justify-center rounded-full text-2xl\", toneDisc[tone])}>\n {icon}\n </span>\n )}\n <div className=\"text-lg font-semibold text-text\">{title}</div>\n {description && <div className=\"max-w-sm text-sm leading-relaxed text-text-muted\">{description}</div>}\n {actions && <div className=\"flex gap-2 pt-1.5\">{actions}</div>}\n </div>\n );\n}\n","import React from \"react\";\nimport { cn } from \"../utils/cn\";\n\nexport interface KbdProps extends React.HTMLAttributes<HTMLElement> {\n /** Key label, e.g. \"⌘K\", \"E\", \"↵\". */\n children: React.ReactNode;\n}\n\n/**\n * Keyboard-shortcut chip (the `⌘K` / `E` / `↵` hints in the redesign).\n *\n * @example\n * ```tsx\n * Zoeken <Kbd>⌘K</Kbd>\n * ```\n */\nexport function Kbd({ children, className, ...props }: KbdProps) {\n return (\n <kbd\n className={cn(\n \"inline-flex items-center rounded border border-border px-1.5 py-px text-xs font-medium leading-none text-text-muted\",\n className,\n )}\n {...props}\n >\n {children}\n </kbd>\n );\n}\n","import React from \"react\";\nimport { cn } from \"../utils/cn\";\n\nexport interface ProgressBarProps extends React.HTMLAttributes<HTMLDivElement> {\n /** Completion 0–100 (clamped). */\n value: number;\n /** Fill tone. */\n variant?: \"accent\" | \"success\";\n /** Track height. */\n size?: \"sm\" | \"md\";\n}\n\nconst trackSizes: Record<NonNullable<ProgressBarProps[\"size\"]>, string> = {\n sm: \"h-1\",\n md: \"h-1.5\",\n};\n\nconst fillVariants: Record<NonNullable<ProgressBarProps[\"variant\"]>, string> = {\n accent: \"bg-accent\",\n success: \"bg-success\",\n};\n\n/**\n * Slim determinate progress bar (focus queue progress, subtask completion).\n * Token-driven and mode-aware.\n *\n * @example\n * ```tsx\n * <ProgressBar value={40} />\n * <ProgressBar value={3 / 7 * 100} variant=\"success\" size=\"sm\" />\n * ```\n */\nexport function ProgressBar({ value, variant = \"accent\", size = \"md\", className, ...props }: ProgressBarProps) {\n const pct = Math.max(0, Math.min(100, value));\n return (\n <div\n role=\"progressbar\"\n aria-valuenow={Math.round(pct)}\n aria-valuemin={0}\n aria-valuemax={100}\n className={cn(\"w-full overflow-hidden rounded-full bg-surface-hover\", trackSizes[size], className)}\n {...props}\n >\n <div\n className={cn(\"h-full rounded-full transition-[width] duration-300 ease-out\", fillVariants[variant])}\n style={{ width: `${pct}%` }}\n />\n </div>\n );\n}\n","import React from 'react';\nimport { cn } from '../utils/cn';\n\nexport interface SpinnerProps extends React.HTMLAttributes<HTMLDivElement> {\n /**\n * The size of the spinner\n */\n size?: 'xs' | 'sm' | 'md' | 'lg' | 'xl';\n \n /**\n * The color variant of the spinner\n */\n variant?: 'primary' | 'secondary' | 'white' | 'current';\n \n /**\n * Optional label for accessibility\n */\n label?: string;\n \n /**\n * Whether to show the spinner with a label\n */\n showLabel?: boolean;\n}\n\nconst spinnerSizes = {\n xs: 'h-3 w-3',\n sm: 'h-4 w-4',\n md: 'h-6 w-6',\n lg: 'h-8 w-8',\n xl: 'h-12 w-12',\n};\n\nconst spinnerColors = {\n primary: 'text-accent',\n secondary: 'text-text-muted',\n white: 'text-white',\n current: 'text-current',\n};\n\nconst labelSizes = {\n xs: 'text-xs',\n sm: 'text-sm',\n md: 'text-sm',\n lg: 'text-base',\n xl: 'text-lg',\n};\n\n/**\n * Spinner component for loading states\n * \n * @example\n * ```tsx\n * <Spinner size=\"md\" variant=\"primary\" />\n * \n * <Spinner size=\"lg\" variant=\"primary\" showLabel label=\"Loading...\" />\n * \n * <Spinner size=\"sm\" variant=\"white\" />\n * ```\n */\nexport function Spinner({\n size = 'md',\n variant = 'primary',\n label = 'Loading...',\n showLabel = false,\n className,\n ...props\n}: SpinnerProps) {\n return (\n <div\n className={cn(\n 'inline-flex items-center',\n showLabel ? 'flex-col space-y-2' : '',\n className\n )}\n {...props}\n >\n <svg\n className={cn(\n 'animate-spin',\n spinnerSizes[size],\n spinnerColors[variant]\n )}\n fill=\"none\"\n viewBox=\"0 0 24 24\"\n aria-hidden={!showLabel}\n role={showLabel ? 'status' : undefined}\n >\n <circle\n className=\"opacity-25\"\n cx=\"12\"\n cy=\"12\"\n r=\"10\"\n stroke=\"currentColor\"\n strokeWidth=\"4\"\n />\n <path\n className=\"opacity-75\"\n fill=\"currentColor\"\n d=\"M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z\"\n />\n </svg>\n \n {showLabel && (\n <span\n className={cn(\n 'text-text-muted',\n labelSizes[size]\n )}\n >\n {label}\n </span>\n )}\n \n {/* Screen reader only text when label is not shown */}\n {!showLabel && (\n <span className=\"sr-only\">{label}</span>\n )}\n </div>\n );\n} ","import React from \"react\";\nimport { cn } from \"../utils/cn\";\n\nexport interface StatusDotProps {\n /**\n * Meaning, not colour. `neutral` is the off/idle state; `accent` marks\n * unread; the rest follow the status tokens.\n */\n tone?:\n | \"neutral\" | \"accent\" | \"success\" | \"warning\" | \"danger\" | \"info\" | \"note\"\n /** Identity without status — an inbox, a speaker. See --color-cat-*. */\n | \"cat-1\" | \"cat-2\" | \"cat-3\" | \"cat-4\" | \"cat-5\";\n /** Square instead of round — the marker style used for inbox identity. */\n shape?: \"round\" | \"square\";\n /** Slow pulse for something live: an active call, a running recording. */\n pulse?: boolean;\n /**\n * Accessible name. Without one the dot is decorative and hidden from\n * assistive tech, which is right when adjacent text already says the state.\n */\n label?: string;\n className?: string;\n}\n\nconst tones: Record<NonNullable<StatusDotProps[\"tone\"]>, string> = {\n neutral: \"bg-text-disabled\",\n accent: \"bg-accent\",\n success: \"bg-success\",\n warning: \"bg-warning\",\n danger: \"bg-danger\",\n info: \"bg-info\",\n note: \"bg-note\",\n \"cat-1\": \"bg-cat-1\",\n \"cat-2\": \"bg-cat-2\",\n \"cat-3\": \"bg-cat-3\",\n \"cat-4\": \"bg-cat-4\",\n \"cat-5\": \"bg-cat-5\",\n};\n\n/**\n * Small state marker: presence, session state, unread, live recording.\n *\n * Replaces a scatter of hand-rolled `h-2 w-2 rounded-full bg-green-500` spans\n * that used raw palette colours and disagreed on size (8px vs 10px).\n *\n * @example\n * ```tsx\n * <StatusDot tone=\"success\" label=\"Online\" />\n * <StatusDot tone=\"danger\" pulse label=\"Opname loopt\" />\n * ```\n */\nexport function StatusDot({\n tone = \"neutral\",\n shape = \"round\",\n pulse = false,\n label,\n className,\n}: StatusDotProps) {\n return (\n <span\n role={label ? \"img\" : undefined}\n aria-label={label}\n aria-hidden={label ? undefined : true}\n className={cn(\n \"inline-block size-dot shrink-0\",\n shape === \"round\" ? \"rounded-full\" : \"rounded-sm\",\n tones[tone],\n pulse && \"animate-pulse\",\n className\n )}\n />\n );\n}\n","import React from \"react\";\nimport { cn } from \"../utils/cn\";\n\nexport interface StepIndicatorProps {\n /** Step ids in order. Only the position matters; the ids identify `current`. */\n steps: string[];\n /** Id of the step being shown. Unknown ids render as \"not started\". */\n current: string;\n /**\n * `numbered` draws counted circles joined by a rule — use it when the user\n * needs to know how many steps are left. `dots` is the quieter bar, for a\n * flow whose heading already says where you are.\n */\n variant?: \"numbered\" | \"dots\";\n /**\n * Accessible name. Without one the indicator is treated as decorative, which\n * is right when a heading beside it already announces the current step.\n */\n label?: string;\n className?: string;\n}\n\n/**\n * Progress through a short, linear flow.\n *\n * @example\n * ```tsx\n * <StepIndicator steps={[\"provider\", \"channel\", \"owner\"]} current={step} />\n * <StepIndicator steps={[\"intent\", \"channel\", \"address\"]} current={step} variant=\"dots\" />\n * ```\n */\nexport function StepIndicator({\n steps,\n current,\n variant = \"numbered\",\n label,\n className,\n}: StepIndicatorProps) {\n const activeIndex = steps.indexOf(current);\n const shared = { role: label ? \"group\" : undefined, \"aria-label\": label, \"aria-hidden\": label ? undefined : true };\n\n if (variant === \"dots\") {\n return (\n <div {...shared} className={cn(\"flex items-center gap-1.5\", className)}>\n {steps.map((step, i) => (\n <span\n key={step}\n className={cn(\n \"h-step-bar rounded-full transition-all duration-fast ease-out\",\n i === activeIndex ? \"w-5 bg-accent\" : \"w-3.5\",\n i < activeIndex && \"bg-border-strong\",\n i > activeIndex && \"bg-border\"\n )}\n />\n ))}\n </div>\n );\n }\n\n return (\n <div {...shared} className={cn(\"flex items-center gap-2\", className)}>\n {steps.map((step, i) => (\n <div key={step} className=\"flex items-center gap-2\">\n <span\n aria-current={i === activeIndex ? \"step\" : undefined}\n className={cn(\n \"flex size-tile-sm items-center justify-center rounded-full text-xs font-medium\",\n i === activeIndex && \"bg-accent text-accent-fg\",\n i < activeIndex && \"bg-accent-soft text-accent\",\n i > activeIndex && \"bg-surface-hover text-text-muted\"\n )}\n >\n {i + 1}\n </span>\n {i < steps.length - 1 && <span className=\"h-px w-8 bg-border-strong\" />}\n </div>\n ))}\n </div>\n );\n}\n","import DOMPurify from \"dompurify\";\nimport type { Components } from \"react-markdown\";\nimport Markdown from \"react-markdown\";\nimport remarkGfm from \"remark-gfm\";\nimport { cn } from \"../utils/cn\";\n\n/**\n * Rendert tekst die óf markdown óf HTML kan zijn — één component voor alle\n * plekken waar door mensen of door een model geschreven tekst op het scherm komt.\n *\n * Waarom beide vormen: dezelfde velden worden door twee soorten schrijvers\n * gevuld. Een interne notitie komt als rich HTML uit de mention-composer, maar\n * als markdown uit een AI-tool of playbook. Wie er maar één van de twee rendert,\n * laat de andere als losse tekens staan — dat is waar `**5MB**` vandaan komt.\n *\n * - **HTML** → gesanitized met DOMPurify en als HTML gezet. Nooit ongefilterd:\n * de tekst kan van een model of van een externe provider komen.\n * - **markdown** → react-markdown met remark-gfm (tabellen, task lists,\n * doorhalen, autolinks). Die emit géén rauwe HTML, dus dat pad kan niets\n * injecteren.\n *\n * Beide takken worden bewust gelijk gestyled met semantische tokens, zodat een\n * notitie er hetzelfde uitziet of hij nu uit de composer of uit een playbook\n * komt. De HTML-tak heeft daarvoor descendant-classes nodig: Tailwind's preflight\n * haalt de browser-defaults van `ul`/`ol` weg, dus zonder deze regels verliest\n * gesanitizede HTML z'n opsommingstekens.\n */\n\nconst HTML_TAG = /<[a-z][\\s\\S]*>/i;\n\n/** Styling voor de HTML-tak; spiegelt de `components`-map hieronder. */\nconst HTML_PROSE = [\n \"[&_p]:my-1.5 [&_p:first-child]:mt-0 [&_p:last-child]:mb-0 [&_p]:leading-relaxed\",\n \"[&_a]:text-accent [&_a]:underline [&_a]:underline-offset-2\",\n \"[&_strong]:font-semibold [&_em]:italic\",\n \"[&_ul]:my-1.5 [&_ul]:list-disc [&_ul]:pl-5 [&_ol]:my-1.5 [&_ol]:list-decimal [&_ol]:pl-5\",\n \"[&_li]:leading-relaxed\",\n \"[&_h1]:mb-1 [&_h1]:mt-2 [&_h1]:font-semibold [&_h2]:mb-1 [&_h2]:mt-2 [&_h2]:font-semibold [&_h3]:mb-1 [&_h3]:mt-2 [&_h3]:font-semibold\",\n \"[&_blockquote]:my-1.5 [&_blockquote]:border-l-2 [&_blockquote]:border-border [&_blockquote]:pl-3 [&_blockquote]:text-text-muted\",\n \"[&_hr]:my-2 [&_hr]:border-border\",\n \"[&_pre]:my-1.5 [&_pre]:overflow-x-auto [&_pre]:rounded-md [&_pre]:bg-surface-sunk [&_pre]:p-2 [&_pre]:text-xs\",\n \"[&_code]:rounded-sm [&_code]:bg-surface-sunk [&_code]:px-1 [&_code]:py-0.5 [&_code]:font-mono [&_code]:text-xs\",\n \"[&_pre_code]:bg-transparent [&_pre_code]:p-0\",\n \"[&_table]:my-1.5 [&_table]:w-full [&_table]:border-collapse [&_table]:text-xs\",\n \"[&_th]:border [&_th]:border-border [&_th]:px-2 [&_th]:py-1 [&_th]:text-left [&_th]:font-semibold\",\n \"[&_td]:border [&_td]:border-border [&_td]:px-2 [&_td]:py-1\",\n].join(\" \");\n\nconst components: Components = {\n p: (props) => <p className=\"my-1.5 leading-relaxed first:mt-0 last:mb-0\" {...props} />,\n a: (props) => (\n <a className=\"text-accent underline underline-offset-2 hover:opacity-80\" target=\"_blank\" rel=\"noopener noreferrer\" {...props} />\n ),\n strong: (props) => <strong className=\"font-semibold\" {...props} />,\n em: (props) => <em className=\"italic\" {...props} />,\n ul: (props) => <ul className=\"my-1.5 list-disc space-y-0.5 pl-5\" {...props} />,\n ol: (props) => <ol className=\"my-1.5 list-decimal space-y-0.5 pl-5\" {...props} />,\n li: (props) => <li className=\"leading-relaxed\" {...props} />,\n h1: (props) => <h1 className=\"mb-1 mt-2 text-md font-semibold first:mt-0\" {...props} />,\n h2: (props) => <h2 className=\"mb-1 mt-2 text-base font-semibold first:mt-0\" {...props} />,\n h3: (props) => <h3 className=\"mb-1 mt-2 text-base font-semibold first:mt-0\" {...props} />,\n blockquote: (props) => (\n <blockquote className=\"my-1.5 border-l-2 border-border pl-3 text-text-muted\" {...props} />\n ),\n hr: (props) => <hr className=\"my-2 border-border\" {...props} />,\n pre: (props) => (\n <pre className=\"my-1.5 overflow-x-auto rounded-md bg-surface-sunk p-2 text-xs\" {...props} />\n ),\n code: ({ className, children, ...props }) => {\n const content = String(children ?? \"\");\n const isBlock = /language-/.test(className ?? \"\") || content.includes(\"\\n\");\n return isBlock ? (\n <code className=\"font-mono text-xs\" {...props}>{children}</code>\n ) : (\n <code className=\"rounded-sm bg-surface-sunk px-1 py-0.5 font-mono text-xs\" {...props}>{children}</code>\n );\n },\n table: (props) => (\n <div className=\"my-1.5 overflow-x-auto\">\n <table className=\"w-full border-collapse text-xs\" {...props} />\n </div>\n ),\n th: (props) => <th className=\"border border-border px-2 py-1 text-left font-semibold\" {...props} />,\n td: (props) => <td className=\"border border-border px-2 py-1\" {...props} />,\n};\n\nexport interface RichTextProps {\n /** Markdown of HTML; welke van de twee wordt gedetecteerd. */\n text: string | null | undefined;\n /** Extra classes op de wrapper (bv. `text-sm` of een line-clamp). */\n className?: string;\n /**\n * Forceer een tak in plaats van te detecteren. Alleen nodig als je zeker\n * weet wat je hebt en de heuristiek in de weg zit (bv. platte tekst die\n * toevallig op een tag lijkt).\n */\n as?: \"markdown\" | \"html\";\n}\n\n/** Veilig gerenderde markdown-of-HTML tekst. */\nexport function RichText({ text, className, as }: RichTextProps) {\n const src = text ?? \"\";\n const isHtml = as ? as === \"html\" : HTML_TAG.test(src);\n\n if (isHtml) {\n return (\n <div\n className={cn(\"break-words\", HTML_PROSE, className)}\n dangerouslySetInnerHTML={{ __html: DOMPurify.sanitize(src, { ADD_ATTR: [\"target\", \"rel\"] }) }}\n />\n );\n }\n\n return (\n <div className={cn(\"break-words\", className)}>\n <Markdown remarkPlugins={[remarkGfm]} components={components}>\n {src}\n </Markdown>\n </div>\n );\n}\n","import type { ArtifactBlock, ArtifactRuntime, ArtifactTone } from \"@opencxh/domain\";\nimport { cn } from \"../utils/cn\";\nimport { RichText } from \"./RichText\";\n\nexport interface ArtifactViewProps {\n blocks: ArtifactBlock[];\n /** Alles behalve `\"inert\"` wordt geweigerd. Zie de klassenoot hierboven. */\n runtime?: ArtifactRuntime;\n className?: string;\n}\n\n/** Statisch, want `text-${tone}-fg` genereert niets (Tailwind scant letterlijk). */\nconst KPI_TONE: Record<ArtifactTone, string> = {\n info: \"text-info-fg\",\n success: \"text-success-fg\",\n warning: \"text-warning-fg\",\n destructive: \"text-danger-fg\",\n};\n\nconst CALLOUT_TONE: Record<ArtifactTone, string> = {\n info: \"bg-info-soft border-info-border\",\n success: \"bg-success-soft border-success-border\",\n warning: \"bg-warning-soft border-warning-border\",\n destructive: \"bg-danger-soft border-danger-border\",\n};\n\n/** Eén tot vier tegels op een rij; ook statisch, om dezelfde reden. */\nconst KPI_COLUMNS: Record<number, string> = {\n 1: \"grid-cols-1\",\n 2: \"grid-cols-2\",\n 3: \"grid-cols-3\",\n 4: \"grid-cols-4\",\n};\n\nfunction Block({ block }: { block: ArtifactBlock }) {\n switch (block.type) {\n case \"heading\":\n if (block.level === 1) {\n return <h1 className=\"text-2xl font-semibold tracking-tight text-text\">{block.text}</h1>;\n }\n if (block.level === 2) {\n return <h2 className=\"pt-2 text-base font-semibold tracking-tight text-text\">{block.text}</h2>;\n }\n return <h3 className=\"pt-1 text-sm font-semibold text-text\">{block.text}</h3>;\n\n case \"paragraph\":\n return <RichText as=\"markdown\" text={block.text} className=\"text-sm text-text\" />;\n\n case \"quote\":\n return (\n <blockquote className=\"border-l-2 border-border pl-3.5\">\n <RichText as=\"markdown\" text={block.text} className=\"text-sm text-text-muted\" />\n </blockquote>\n );\n\n case \"code\":\n return (\n <pre className=\"overflow-x-auto rounded-lg bg-surface-sunk p-3 text-xs\">\n <code className=\"font-mono\">{block.text}</code>\n </pre>\n );\n\n case \"divider\":\n return <hr className=\"border-border-subtle\" />;\n\n case \"list\": {\n const List = block.style === \"numbered\" ? \"ol\" : \"ul\";\n return (\n <List\n className={cn(\n \"flex flex-col gap-2 pl-5 text-sm text-text\",\n block.style === \"numbered\" ? \"list-decimal\" : \"list-disc\",\n )}\n >\n {block.items.map((item, index) => (\n <li key={index} className=\"leading-relaxed marker:text-text-subtle\">\n {item.lead && <strong className=\"font-semibold\">{item.lead} </strong>}\n <RichText as=\"markdown\" text={item.text} className=\"inline\" />\n </li>\n ))}\n </List>\n );\n }\n\n case \"table\":\n return (\n <figure className=\"m-0\">\n {/* Brede tabellen scrollen in hun eigen doos; het document zelf mag\n nooit horizontaal schuiven. */}\n <div className=\"overflow-x-auto rounded-lg ring-1 ring-border\">\n <table className=\"w-full border-collapse text-sm\">\n <thead>\n <tr className=\"bg-surface-sunk\">\n {block.columns.map((column, index) => (\n <th\n key={index}\n className={cn(\n \"px-4 py-2.5 text-xs font-semibold text-text-muted\",\n column.align === \"right\" ? \"text-right\" : \"text-left\",\n )}\n >\n {column.label}\n </th>\n ))}\n </tr>\n </thead>\n <tbody>\n {block.rows.map((row, rowIndex) => (\n <tr key={rowIndex} className=\"border-t border-border-subtle\">\n {row.map((value, cellIndex) => (\n <td\n key={cellIndex}\n className={cn(\n \"px-4 py-2.5 tabular-nums text-text\",\n block.columns[cellIndex]?.align === \"right\" ? \"text-right\" : \"text-left\",\n )}\n >\n {value}\n </td>\n ))}\n </tr>\n ))}\n </tbody>\n </table>\n </div>\n {block.caption && (\n <figcaption className=\"pt-2 text-xs italic text-text-subtle\">{block.caption}</figcaption>\n )}\n </figure>\n );\n\n case \"kpi\":\n return (\n <div className={cn(\"grid gap-3\", KPI_COLUMNS[block.items.length] ?? \"grid-cols-4\")}>\n {block.items.map((item, index) => (\n <div key={index} className=\"rounded-lg bg-surface-sunk px-4 py-3.5\">\n <div\n className={cn(\n \"text-2xl font-semibold tracking-tight\",\n item.tone ? KPI_TONE[item.tone] : \"text-text\",\n )}\n >\n {item.value}\n </div>\n <div className=\"pt-0.5 text-xs text-text-muted\">{item.label}</div>\n </div>\n ))}\n </div>\n );\n\n case \"callout\":\n return (\n <div className={cn(\"rounded-lg border px-4 py-3\", CALLOUT_TONE[block.tone])}>\n {block.title && <div className=\"pb-0.5 text-sm font-semibold text-text\">{block.title}</div>}\n <RichText as=\"markdown\" text={block.text} className=\"text-sm text-text\" />\n </div>\n );\n\n default:\n // Onbekend blok: overslaan, niet crashen.\n return null;\n }\n}\n\nexport function ArtifactView({ blocks, runtime = \"inert\", className }: ArtifactViewProps) {\n if (runtime !== \"inert\") {\n return (\n <div className={cn(\"rounded-lg border border-warning-border bg-warning-soft px-4 py-3\", className)}>\n <div className=\"text-sm font-semibold text-text\">Deze versie kan hier niet getoond worden</div>\n <div className=\"pt-0.5 text-xs text-text-muted\">\n Hij is opgeslagen als <code className=\"font-mono\">{runtime}</code>, en deze weergave tekent\n alleen inerte inhoud.\n </div>\n </div>\n );\n }\n\n return (\n <article className={cn(\"flex flex-col gap-4\", className)}>\n {blocks.map((block, index) => (\n <Block key={block.block_id ?? index} block={block} />\n ))}\n </article>\n );\n}\n","import { Sparkles } from \"lucide-react\";\nimport React from \"react\";\nimport { cn } from \"../utils/cn\";\n\nexport interface AssistantCardProps extends Omit<React.HTMLAttributes<HTMLDivElement>, \"title\"> {\n /** Card heading (e.g. \"Briefing van je assistent\", \"Voorstel van de assistent\"). */\n title: React.ReactNode;\n /** Leading icon; defaults to the lucide Sparkles icon. */\n icon?: React.ReactNode;\n /** Optional action rendered on the header's right (e.g. a \"Gebruiken\" button). */\n action?: React.ReactNode;\n /** Body content. */\n children?: React.ReactNode;\n}\n\n/**\n * AI-assistant card shell — the tinted \"Briefing / Voorstel van de assistent\"\n * surface used on Mijn dag and in the Focus queue. Uses the `--assistant-*`\n * design-system tokens so the tint is mode-aware.\n *\n * @example\n * ```tsx\n * <AssistantCard title=\"Voorstel van de assistent\" action={<Button>Gebruiken</Button>}>\n * Marc wacht 12 min op WhatsApp — concept staat klaar.\n * </AssistantCard>\n * ```\n */\nexport function AssistantCard({ title, icon = <Sparkles className=\"size-icon-md\" aria-hidden />, action, children, className, ...props }: AssistantCardProps) {\n return (\n <div\n className={cn(\n \"flex flex-col gap-2 rounded-xl border p-4\",\n \"border-assistant-border bg-assistant-soft\",\n className,\n )}\n {...props}\n >\n <div className=\"flex items-center gap-2 text-assistant\">\n <span aria-hidden>{icon}</span>\n <span className=\"text-sm font-semibold\">{title}</span>\n {action && <span className=\"ml-auto\">{action}</span>}\n </div>\n {children && <div className=\"text-sm leading-relaxed text-text\">{children}</div>}\n </div>\n );\n}\n","import React from \"react\";\nimport { cn } from \"../utils/cn\";\nimport { identityPlateClass } from \"../utils/identity\";\n\n/**\n * Plate colour. `default` is the neutral disc used everywhere a monogram is just\n * an identity marker.\n *\n * `identity` derives the colour from `name`, so the same person or team is the\n * same colour on every surface — see {@link identityPlateClass}. Use it in a\n * list of many people; use `default` where there is only one plate on screen\n * and colour would carry no information.\n *\n * The other three are for a message thread, where the plate answers \"which side\n * is this from\" before you read a word: `in` is the other party, `out` is us\n * (ink, so it reads as ours in both themes) and `note` is an internal remark.\n * Each is a fill with its own foreground — a fill cannot borrow a colour from\n * the ramp, because the ramp does not change between light and dark.\n */\nexport type AvatarTone = \"default\" | \"identity\" | \"in\" | \"out\" | \"note\";\n\nconst toneClasses: Record<Exclude<AvatarTone, \"identity\">, string> = {\n default: \"bg-avatar text-avatar-fg\",\n in: \"bg-avatar-in text-avatar-in-fg\",\n out: \"bg-accent text-accent-fg\",\n note: \"bg-avatar-note text-avatar-note-fg\",\n};\n\nexport interface AvatarProps {\n /** Full name; used for the initials fallback and alt/title text */\n name?: string;\n /** Optional image URL; falls back to initials when absent or on load error */\n src?: string;\n /** Plate colour; see {@link AvatarTone}. */\n tone?: AvatarTone;\n /** Size preset */\n size?: \"xs\" | \"sm\" | \"md\" | \"lg\";\n /** Additional CSS classes */\n className?: string;\n /** Override the title attribute (defaults to `name`) */\n title?: string;\n}\n\nconst sizeClasses: Record<NonNullable<AvatarProps[\"size\"]>, string> = {\n xs: \"w-5 h-5 text-xs\",\n sm: \"w-6 h-6 text-xs\",\n md: \"w-7 h-7 text-base\",\n lg: \"w-9 h-9 text-sm\",\n};\n\nfunction initials(name?: string): string {\n if (!name) return \"?\";\n // Split op alles wat geen letter/cijfer is (spatie, @, ., -, _, …) zodat\n // adressen als \"mail-team@x.nl\" schone initialen geven (\"MT\"), niet \"M-\".\n const parts = name.trim().split(/[^\\p{L}\\p{N}]+/u).filter(Boolean);\n if (parts.length >= 2) return (parts[0][0] + parts[1][0]).toUpperCase();\n if (parts.length === 1) return parts[0].slice(0, 2).toUpperCase();\n return \"?\";\n}\n\n/**\n * Circular avatar: renders the photo when `src` is set (falling back to\n * initials on error), otherwise a monogram derived from `name`.\n */\nexport const Avatar: React.FC<AvatarProps> = ({ name, src, tone = \"default\", size = \"sm\", className, title }) => {\n const [errored, setErrored] = React.useState(false);\n const base = cn(\n // Its own token and not `surface-hover`: at 0.972 the plate was within a few\n // percent of every surface it sits on, so the monogram floated instead of\n // sitting in a disc.\n \"inline-flex items-center justify-center rounded-full overflow-hidden shrink-0 font-semibold select-none\",\n // `identity` is seeded on the name, so the same person keeps their colour\n // wherever they appear; the fixed tones stay as they were.\n tone === \"identity\" ? identityPlateClass(name) : toneClasses[tone],\n sizeClasses[size],\n className,\n );\n\n if (src && !errored) {\n return (\n <img\n src={src}\n alt={name ?? \"\"}\n title={title ?? name}\n className={cn(base, \"object-cover\")}\n onError={() => setErrored(true)}\n />\n );\n }\n\n return (\n <span className={base} title={title ?? name} aria-label={name}>\n {initials(name)}\n </span>\n );\n};\n","import React from \"react\";\nimport { cn } from \"../utils/cn\";\nimport { Avatar, type AvatarProps } from \"./Avatar\";\n\nexport interface AvatarStackPerson {\n id?: string;\n name?: string;\n src?: string;\n /** Owner / assignee — rendered with an accent ring */\n owner?: boolean;\n /** Whether this person has seen the item; unseen renders dimmed */\n seen?: boolean;\n}\n\nexport interface AvatarStackProps {\n people: AvatarStackPerson[];\n /** Max avatars to show before collapsing the rest into a \"+N\" chip */\n max?: number;\n size?: AvatarProps[\"size\"];\n className?: string;\n}\n\n// Panel-coloured ring so overlapping avatars stay visually separated; the\n// owner gets an extra accent halo on top of it.\nconst RING = \"ring-surface\";\nconst OWNER_RING = \"ring-surface-accent\";\n\n/**\n * Overlapping row of avatars with an optional \"+N\" overflow chip. Unseen\n * people are dimmed; the owner carries an accent ring.\n */\nexport const AvatarStack: React.FC<AvatarStackProps> = ({ people, max = 4, size = \"sm\", className }) => {\n if (people.length === 0) return null;\n const shown = people.slice(0, max);\n const overflow = people.length - shown.length;\n\n return (\n <span className={cn(\"inline-flex items-center\", className)}>\n {shown.map((p, i) => (\n <Avatar\n key={p.id ?? `${p.name}-${i}`}\n name={p.name}\n src={p.src}\n size={size}\n title={p.name ? (p.seen === false ? `${p.name} — nog niet gelezen` : p.name) : undefined}\n className={cn(\n i > 0 && \"-ml-2\",\n p.owner ? OWNER_RING : RING,\n p.seen === false && \"opacity-40\",\n )}\n />\n ))}\n {overflow > 0 && (\n <span\n className={cn(\n // Same fill as an Avatar plate, so the \"+3\" reads as one more disc\n // in the row rather than a gap at the end of it.\n \"inline-flex items-center justify-center rounded-full shrink-0 -ml-2 font-semibold bg-avatar text-avatar-fg\",\n size === \"xs\" ? \"w-5 h-5 text-xs\" : size === \"md\" ? \"w-7 h-7 text-xs\" : size === \"lg\" ? \"w-9 h-9 text-xs\" : \"w-6 h-6 text-xs\",\n RING,\n )}\n >\n +{overflow}\n </span>\n )}\n </span>\n );\n};\n","import React from \"react\";\nimport { cn } from \"../utils/cn\";\nimport { identityPlateClass } from \"../utils/identity\";\n\n/** Communication channel keys the redesign colour-codes. */\nexport type ChannelKey = \"mail\" | \"wa\" | \"chat\" | \"tel\" | \"note\";\n\nexport interface ChannelBadgeProps {\n /**\n * Channel — drives the colour. A known key uses that channel's tokens; any\n * other string (a provider that brought its own channel along) gets a stable\n * colour derived from the string itself, so ten custom channels stay ten\n * distinguishable colours instead of ten identical grey tiles.\n */\n channel?: ChannelKey | string;\n /** Glyph or short label inside the tile (e.g. an icon, or an initial). */\n children?: React.ReactNode;\n /** Tile size. */\n size?: \"sm\" | \"md\" | \"lg\";\n className?: string;\n title?: string;\n}\n\n/**\n * Channel key → semantic token pair. The keys are the redesign's shorthand\n * (`wa`, `tel`); the tokens spell the channel out (`whatsapp`, `phone`).\n * Written as whole class names so Tailwind can find them.\n */\nconst CH: Record<ChannelKey, { fg: string; bg: string }> = {\n mail: { fg: \"text-channel-mail-fg\", bg: \"bg-channel-mail-soft\" },\n wa: { fg: \"text-channel-whatsapp-fg\", bg: \"bg-channel-whatsapp-soft\" },\n chat: { fg: \"text-channel-chat-fg\", bg: \"bg-channel-chat-soft\" },\n tel: { fg: \"text-channel-phone-fg\", bg: \"bg-channel-phone-soft\" },\n note: { fg: \"text-channel-note-fg\", bg: \"bg-channel-note-soft\" },\n};\n\nconst sizes: Record<NonNullable<ChannelBadgeProps[\"size\"]>, string> = {\n sm: \"size-avatar-xs rounded-sm text-xs\",\n md: \"size-avatar-sm rounded-md text-xs\",\n lg: \"size-avatar-lg rounded-md text-base\",\n};\n\n/**\n * Coloured channel tile (the glyph-in-rounded-square used across inbox rows,\n * the focus queue, the attention list and Recent tabs). Colours come from the\n * `--color-channel-*` design-system tokens, so it is mode-aware.\n *\n * @example\n * ```tsx\n * <ChannelBadge channel=\"wa\">W</ChannelBadge>\n * <ChannelBadge channel=\"mail\" size=\"lg\"><MailIcon /></ChannelBadge>\n * ```\n */\nexport function ChannelBadge({ channel, children, size = \"md\", className, title }: ChannelBadgeProps) {\n const known = (channel as ChannelKey) in CH ? CH[channel as ChannelKey] : undefined;\n return (\n <span\n title={title}\n className={cn(\n \"inline-flex shrink-0 items-center justify-center font-bold\",\n sizes[size],\n // An undeclared channel used to collapse onto the neutral \"note\" tone,\n // which is also what a real internal note looks like. Deriving from the\n // key keeps it distinguishable and keeps `note` meaning `note`.\n known ? cn(known.fg, known.bg) : channel ? identityPlateClass(channel) : cn(CH.note.fg, CH.note.bg),\n className,\n )}\n >\n {children}\n </span>\n );\n}\n","import React, { useState } from 'react';\nimport { ImageOff } from \"lucide-react\";\nimport { Icon } from \"./Icon\";\nimport { cn } from '../utils/cn';\n\nexport interface ImageProps extends React.ImgHTMLAttributes<HTMLImageElement> {\n /** Image source URL */\n src: string;\n /** Alt text for accessibility */\n alt: string;\n /** Image size preset */\n size?: 'xs' | 'sm' | 'md' | 'lg' | 'xl' | 'full';\n /** Aspect ratio */\n aspectRatio?: 'square' | 'video' | 'portrait' | 'landscape' | 'auto';\n /** Border radius */\n radius?: 'none' | 'sm' | 'md' | 'lg' | 'xl' | 'full';\n /** Whether to show loading state */\n showLoading?: boolean;\n /** Whether to show error state */\n showError?: boolean;\n /** Fallback image URL */\n fallback?: string;\n /** Loading placeholder content */\n loadingContent?: React.ReactNode;\n /** Error placeholder content */\n errorContent?: React.ReactNode;\n /** Additional CSS classes */\n className?: string;\n}\n\n/**\n * Image component with loading states, error handling, and theme integration\n */\nexport const Image: React.FC<ImageProps> = ({\n src,\n alt,\n size = 'md',\n aspectRatio = 'auto',\n radius = 'md',\n showLoading = true,\n showError = true,\n fallback,\n loadingContent,\n errorContent,\n className,\n onLoad,\n onError,\n ...props\n}) => {\n const [isLoading, setIsLoading] = useState(true);\n const [hasError, setHasError] = useState(false);\n const [currentSrc, setCurrentSrc] = useState(src);\n\n const handleLoad = (event: React.SyntheticEvent<HTMLImageElement>) => {\n setIsLoading(false);\n setHasError(false);\n onLoad?.(event);\n };\n\n const handleError = (event: React.SyntheticEvent<HTMLImageElement>) => {\n setIsLoading(false);\n setHasError(true);\n \n // Try fallback if available and not already using it\n if (fallback && currentSrc !== fallback) {\n setCurrentSrc(fallback);\n setHasError(false);\n setIsLoading(true);\n return;\n }\n \n onError?.(event);\n };\n\n const containerClasses = cn(\n 'relative overflow-hidden bg-surface-hover',\n \n // Size variants\n {\n 'w-8 h-8': size === 'xs',\n 'w-12 h-12': size === 'sm',\n 'w-16 h-16': size === 'md',\n 'w-24 h-24': size === 'lg',\n 'w-32 h-32': size === 'xl',\n 'w-full h-full': size === 'full',\n },\n \n // Aspect ratio variants\n {\n 'aspect-square': aspectRatio === 'square',\n 'aspect-video': aspectRatio === 'video',\n 'aspect-portrait': aspectRatio === 'portrait',\n 'aspect-landscape': aspectRatio === 'landscape',\n },\n \n // Border radius variants\n {\n 'rounded-none': radius === 'none',\n 'rounded-sm': radius === 'sm',\n 'rounded-md': radius === 'md',\n 'rounded-lg': radius === 'lg',\n 'rounded-xl': radius === 'xl',\n 'rounded-full': radius === 'full',\n },\n \n className\n );\n\n const imageClasses = cn(\n 'w-full h-full object-cover transition-opacity duration-fast',\n {\n 'opacity-0': isLoading || hasError,\n 'opacity-100': !isLoading && !hasError,\n }\n );\n\n const placeholderClasses = cn(\n 'absolute inset-0 flex items-center justify-center',\n 'text-text-muted'\n );\n\n const defaultLoadingContent = (\n <div className=\"animate-pulse\">\n <div className=\"w-6 h-6 bg-surface-hover rounded\"></div>\n </div>\n );\n\n const defaultErrorContent = (\n <div className=\"text-center\">\n <Icon icon={ImageOff} size=\"lg\" className=\"mx-auto mb-1\" />\n <span className=\"text-xs\">Failed to load</span>\n </div>\n );\n\n return (\n <div className={containerClasses}>\n <img\n {...props}\n src={currentSrc}\n alt={alt}\n className={imageClasses}\n onLoad={handleLoad}\n onError={handleError}\n />\n \n {/* Loading state */}\n {isLoading && showLoading && (\n <div className={placeholderClasses}>\n {loadingContent || defaultLoadingContent}\n </div>\n )}\n \n {/* Error state */}\n {hasError && showError && (\n <div className={placeholderClasses}>\n {errorContent || defaultErrorContent}\n </div>\n )}\n </div>\n );\n}; ","import { ChevronRight, X } from \"lucide-react\";\nimport React from \"react\";\nimport { Checkbox } from \"../input/Checkbox\";\nimport { cn } from \"../utils/cn\";\n\nexport interface ListGroup {\n /** Group key — must match what `groupBy` returns */\n id: string;\n /** Header label; defaults to `id` */\n title?: string;\n /** Override the row count shown on the right */\n count?: number;\n /** Start collapsed (only with `collapsible`) */\n defaultCollapsed?: boolean;\n /**\n * `danger` tints the label and its count — for a section that is a problem\n * by definition (overdue, failed), where the rows themselves carry no\n * marker that the group is the bad one.\n */\n tone?: \"default\" | \"danger\" | \"muted\";\n}\n\nexport interface ListProps<T> {\n /** Rows to render */\n items: T[];\n /** Stable key per row */\n getRowKey?: (item: T, index: number) => string | number;\n /**\n * Row separation. `inset` gives each row a rounded hover plate held off the\n * edge instead of a rule — the treatment for a list of things you tick off\n * (tasks) rather than a table you scan across (the inbox).\n */\n variant?: \"plain\" | \"divided\" | \"bulleted\" | \"inset\";\n /** Leading slot — channel tile, avatar, status dot */\n leading?: (item: T, index: number) => React.ReactNode;\n /** Main content; defaults to `String(item)` */\n renderItem?: (item: T, index: number) => React.ReactNode;\n /** Trailing slot — timestamp, badge, counter */\n trailing?: (item: T, index: number) => React.ReactNode;\n /** Row click */\n onSelect?: (item: T, index: number) => void;\n /**\n * Fired when keyboard focus lands on a row. Lets a consumer mirror the\n * roving focus into its own \"active\" state (what a hand-rolled `useArrowNav`\n * used to provide) without owning the key handling.\n */\n onActiveIndexChange?: (index: number) => void;\n /** Highlighted row (accent wash) */\n isActive?: (item: T, index: number) => boolean;\n /** Bold + accent dot */\n unread?: (item: T, index: number) => boolean;\n /** Deprioritised noise (opacity) */\n dimmed?: (item: T, index: number) => boolean;\n\n /** Group rows under headers. Return the group id for each row. */\n groupBy?: (item: T, index: number) => string;\n /**\n * Group order and labels. Groups missing here are appended in order of first\n * appearance; groups listed here but empty are skipped.\n */\n groups?: ListGroup[];\n /** Header renderer; defaults to label + count */\n renderGroupHeader?: (group: ListGroup, items: T[]) => React.ReactNode;\n /** Headers stick to the top of the scroll container */\n stickyGroupHeaders?: boolean;\n /** Headers become a toggle that folds the group */\n collapsibleGroups?: boolean;\n /** Hide the count on the right of the header */\n hideGroupCount?: boolean;\n\n /** Checkbox column + bulk bar */\n selectable?: boolean;\n /** Selected rows (controlled) */\n selectedItems?: T[];\n /** Selection handler */\n onSelectionChange?: (selected: T[]) => void;\n /** Actions shown in the bulk bar when a selection exists */\n bulkActions?: React.ReactNode;\n\n /**\n * Column-label strip above the rows (\"Van · Gesprek · tijd\"), like the inbox.\n * Align it with the row by reusing the same widths as `renderItem`.\n */\n header?: React.ReactNode;\n /** Keep the column-label strip visible while scrolling */\n stickyHeader?: boolean;\n\n /** Wrap the list in a bordered container */\n bordered?: boolean;\n /** Empty state content */\n emptyContent?: React.ReactNode;\n /** Loading state */\n loading?: boolean;\n /** Number of skeleton rows while loading */\n loadingRows?: number;\n className?: string;\n \"aria-label\"?: string;\n}\n\n/**\n * One action in the bulk dock. Its own component rather than a `Button`\n * variant: the dock is an ink surface, so every ordinary button variant is a\n * light plate on a dark bar. Use it for the `bulkActions` slot.\n *\n * @example\n * ```tsx\n * bulkActions={<>\n * <ListBulkAction icon={<Icon icon={UserPlus} size=\"sm\" />} onClick={assign}>Toewijzen</ListBulkAction>\n * <ListBulkAction icon={<Icon icon={Archive} size=\"sm\" />} onClick={archive}>Archiveren</ListBulkAction>\n * </>}\n * ```\n */\nexport function ListBulkAction({\n icon,\n onClick,\n children,\n}: {\n icon?: React.ReactNode;\n onClick?: () => void;\n children: React.ReactNode;\n}) {\n return (\n <button\n type=\"button\"\n onClick={onClick}\n className={cn(\n \"inline-flex h-control-sm shrink-0 cursor-pointer items-center gap-1.5 rounded-md px-2.5\",\n \"text-sm font-medium whitespace-nowrap\",\n \"transition-colors duration-fast ease-out hover:bg-white/15\",\n \"focus-visible:outline-none focus-visible:focus-ring\"\n )}\n >\n {icon}\n {children}\n </button>\n );\n}\n\n/**\n * List — one row is one object you open, with content of varying length\n * (inbox conversations, notifications, search results). No column headers:\n * hierarchy lives inside the row.\n *\n * Use `Table` instead when you compare values between rows (sortable columns,\n * aligned amounts, select-all in a header).\n *\n * Grouped, like the inbox and task views:\n *\n * @example\n * ```tsx\n * <List\n * items={tasks}\n * getRowKey={(t) => t.id}\n * bordered\n * groupBy={(t) => t.bucket} // \"today\" | \"tomorrow\" | \"later\"\n * groups={[\n * { id: \"today\", title: \"Vandaag\" },\n * { id: \"tomorrow\", title: \"Morgen\" },\n * { id: \"later\", title: \"Later\" },\n * ]}\n * stickyGroupHeaders\n * collapsibleGroups\n * leading={(t) => <ChannelBadge channel={t.channel} size=\"sm\" />}\n * renderItem={(t) => <span className=\"truncate\">{t.title}</span>}\n * trailing={(t) => t.due}\n * unread={(t) => !t.read}\n * />\n * ```\n */\nexport function List<T>({\n items,\n getRowKey,\n variant = \"divided\",\n leading,\n renderItem,\n trailing,\n onSelect,\n onActiveIndexChange,\n isActive,\n unread,\n dimmed,\n groupBy,\n groups,\n renderGroupHeader,\n stickyGroupHeaders = false,\n collapsibleGroups = false,\n hideGroupCount = false,\n selectable = false,\n selectedItems = [],\n onSelectionChange,\n bulkActions,\n header,\n stickyHeader = false,\n bordered = false,\n emptyContent,\n loading = false,\n loadingRows = 4,\n className,\n \"aria-label\": ariaLabel,\n}: ListProps<T>) {\n const [collapsed, setCollapsed] = React.useState<Record<string, boolean>>(() =>\n Object.fromEntries(\n (groups ?? [])\n .filter((g) => g.defaultCollapsed)\n .map((g) => [g.id, true])\n )\n );\n\n const rootRef = React.useRef<HTMLDivElement>(null);\n\n /**\n * Roving focus across the rows. Rows are focusable in DOM order, so this walks\n * them directly rather than tracking an index — grouping and collapsing cannot\n * put it out of sync that way.\n */\n const handleKeyDown = (event: React.KeyboardEvent<HTMLDivElement>) => {\n const keys = [\"ArrowDown\", \"ArrowUp\", \"Home\", \"End\"];\n if (!keys.includes(event.key)) return;\n\n const rows = Array.from(\n rootRef.current?.querySelectorAll<HTMLLIElement>(\"li[data-list-row]\") ?? []\n );\n if (rows.length === 0) return;\n event.preventDefault();\n\n const current = rows.indexOf(document.activeElement as HTMLLIElement);\n const next =\n event.key === \"Home\" ? 0\n : event.key === \"End\" ? rows.length - 1\n : event.key === \"ArrowDown\" ? (current + 1) % rows.length\n : (current - 1 + rows.length) % rows.length;\n\n rows[next]?.focus();\n };\n\n const keyOf = (item: T, index: number) =>\n getRowKey ? getRowKey(item, index) : index;\n\n const isSelected = (item: T) => selectedItems.includes(item);\n\n const toggle = (item: T, checked: boolean) => {\n if (!onSelectionChange) return;\n onSelectionChange(\n checked ? [...selectedItems, item] : selectedItems.filter((i) => i !== item)\n );\n };\n\n const toggleAll = (checked: boolean) =>\n onSelectionChange?.(checked ? [...items] : []);\n\n const container = cn(\n \"flex flex-col\",\n // With a selection open the list has a dock at its foot. Sticky can only\n // park at the bottom of its own box, so on a list shorter than the window\n // the dock hung right under the last row instead of at the bottom of the\n // screen. Growing the box to the height of its parent puts it where it\n // belongs — and only while a selection exists, so an ordinary short list\n // keeps its natural height.\n selectable && selectedItems.length > 0 && \"min-h-full\",\n bordered && \"overflow-hidden rounded-lg border border-border-subtle\",\n className\n );\n\n if (loading) {\n return (\n <div className={container}>\n {Array.from({ length: loadingRows }).map((_, i) => (\n <div\n key={`skeleton-${i}`}\n className={cn(\n \"flex animate-pulse items-center gap-3 px-4 py-2\",\n variant === \"divided\" && i > 0 && \"border-t border-border-subtle\"\n )}\n >\n <span className=\"size-tile-sm shrink-0 rounded-md bg-surface-hover\" />\n <span className=\"h-3 w-30 shrink-0 rounded-sm bg-surface-hover\" />\n <span className=\"h-3 flex-1 rounded-sm bg-surface-hover\" />\n <span className=\"h-3 w-8 shrink-0 rounded-sm bg-surface-hover\" />\n </div>\n ))}\n </div>\n );\n }\n\n if (items.length === 0 && emptyContent) {\n return <div className={container}>{emptyContent}</div>;\n }\n\n const allSelected = items.length > 0 && selectedItems.length === items.length;\n const someSelected = selectedItems.length > 0 && !allSelected;\n\n // ---- rows, in one flat pass so `index` keeps pointing at the source item ----\n const renderRow = (item: T, index: number, firstInBlock: boolean) => {\n const active = isActive?.(item, index) ?? false;\n const isUnread = unread?.(item, index) ?? false;\n const isDimmed = dimmed?.(item, index) ?? false;\n const selected = selectable && isSelected(item);\n\n return (\n <li\n key={keyOf(item, index)}\n // A clickable row cannot be a <button>: it holds a checkbox and may hold\n // trailing actions, and buttons may not nest. Button semantics are put on\n // the row instead, so it is reachable, operable and announced correctly.\n {...(onSelect\n ? {\n role: \"button\" as const,\n tabIndex: 0,\n \"data-list-row\": \"\",\n \"aria-current\": active || undefined,\n onClick: () => onSelect(item, index),\n onFocus: () => onActiveIndexChange?.(index),\n onKeyDown: (event: React.KeyboardEvent<HTMLLIElement>) => {\n if (event.key !== \"Enter\" && event.key !== \" \") return;\n // Space scrolls the page by default.\n event.preventDefault();\n onSelect(item, index);\n },\n }\n : {})}\n className={cn(\n \"flex items-center gap-3 text-base\",\n \"transition-colors duration-fast ease-out\",\n variant === \"inset\" ? \"mx-2 rounded-lg px-3 py-2.5\" : \"px-5 py-2.5\",\n variant === \"divided\" && !firstInBlock && \"border-t border-border-subtle\",\n onSelect && \"cursor-pointer focus-visible:outline-none focus-visible:focus-ring\",\n // An unread row is tinted, not bolded: at five columns a bold row\n // shouts across all of them, while the tint marks the row and leaves\n // the consumer free to weight only the sender and the subject.\n active || selected\n ? \"bg-accent-soft text-text\"\n : isUnread\n ? cn(\"bg-surface-unread\", onSelect && \"hover:bg-surface-unread-hover\")\n : onSelect && \"hover:bg-surface-hover\",\n // Read rows stay at full opacity — fading them also fades the avatars\n // and team dots, which is exactly the identity you scan by. They read\n // as secondary through weight and text colour instead.\n isDimmed && \"text-text-muted\"\n )}\n >\n {selectable && (\n <span onClick={(e) => e.stopPropagation()}>\n <Checkbox\n checked={isSelected(item)}\n onChange={(e) => toggle(item, e.target.checked)}\n aria-label=\"Rij selecteren\"\n />\n </span>\n )}\n\n {variant === \"bulleted\" && (\n <span\n aria-hidden\n className=\"mt-2 size-1.5 shrink-0 self-start rounded-full bg-border-strong\"\n />\n )}\n\n {leading && <span className=\"shrink-0\">{leading(item, index)}</span>}\n\n <div className=\"flex min-w-0 flex-1 items-center gap-2\">\n {renderItem ? renderItem(item, index) : String(item)}\n </div>\n\n {trailing && (\n <span className=\"shrink-0 text-xs text-text-subtle\">\n {trailing(item, index)}\n </span>\n )}\n </li>\n );\n };\n\n const body = (() => {\n if (!groupBy) {\n return items.map((item, index) => renderRow(item, index, index === 0));\n }\n\n // group id -> [{ item, index }], first-appearance order\n const buckets = new Map<string, { item: T; index: number }[]>();\n items.forEach((item, index) => {\n const id = groupBy(item, index);\n if (!buckets.has(id)) buckets.set(id, []);\n buckets.get(id)!.push({ item, index });\n });\n\n const declared = groups ?? [];\n const order: ListGroup[] = [\n ...declared.filter((g) => buckets.has(g.id)),\n ...[...buckets.keys()]\n .filter((id) => !declared.some((g) => g.id === id))\n .map((id) => ({ id })),\n ];\n\n return order.flatMap((group, groupIndex) => {\n const rows = buckets.get(group.id) ?? [];\n const isCollapsed = collapsibleGroups && collapsed[group.id];\n const label = group.title ?? group.id;\n const count = group.count ?? rows.length;\n\n const header = (\n <li\n key={`group-${group.id}`}\n onClick={\n collapsibleGroups\n ? () =>\n setCollapsed((prev) => ({ ...prev, [group.id]: !prev[group.id] }))\n : undefined\n }\n className={cn(\n // A caption over its rows, not a band across the table: same\n // surface as the rows, no rules, and the count as a quiet pill.\n // The old grey uppercase strip read as a second column header.\n \"flex items-center gap-2.5 bg-surface px-5 pb-1.5 text-base font-semibold\",\n groupIndex > 0 ? \"pt-5\" : \"pt-3\",\n group.tone === \"danger\" ? \"text-danger-fg\"\n : group.tone === \"muted\" ? \"text-text-subtle\"\n : \"text-text\",\n stickyGroupHeaders && \"sticky z-10\",\n collapsibleGroups && \"cursor-pointer select-none\"\n )}\n aria-expanded={collapsibleGroups ? !isCollapsed : undefined}\n // the column strip is 28px tall, so grouped headers park underneath it\n style={stickyGroupHeaders ? { top: stickyHeader ? 28 : 0 } : undefined}\n >\n {renderGroupHeader ? (\n renderGroupHeader(group, rows.map((r) => r.item))\n ) : (\n <>\n {collapsibleGroups && (\n <ChevronRight\n aria-hidden\n className={cn(\n \"size-icon-md shrink-0 text-text-subtle transition-transform duration-fast ease-out\",\n !isCollapsed && \"rotate-90\"\n )}\n />\n )}\n <span>{label}</span>\n {!hideGroupCount && (\n <span\n className={cn(\n \"rounded-full px-2 text-xs font-normal tabular-nums\",\n group.tone === \"danger\"\n ? \"bg-danger-soft text-danger-fg\"\n : \"bg-surface-sunk text-text-subtle\"\n )}\n >\n {count}\n </span>\n )}\n </>\n )}\n </li>\n );\n\n if (isCollapsed) return [header];\n\n return [\n header,\n ...rows.map(({ item, index }, rowIndex) =>\n renderRow(item, index, rowIndex === 0)\n ),\n ];\n });\n })();\n\n return (\n <div ref={rootRef} className={container} onKeyDown={onSelect ? handleKeyDown : undefined}>\n {header && (\n <div\n className={cn(\n // h-row-sm keeps the strip exactly 28px, which is the offset the\n // sticky group headers park against.\n \"flex h-row-sm items-end gap-3 border-b border-border bg-surface px-5 pb-2\",\n \"text-xs font-semibold uppercase tracking-wider text-text-disabled\",\n stickyHeader && \"sticky top-0 z-20\"\n )}\n >\n {selectable && (\n <span className=\"flex items-center\">\n <Checkbox\n checked={allSelected}\n indeterminate={someSelected}\n onChange={(e) => toggleAll(e.target.checked)}\n aria-label=\"Alles selecteren\"\n />\n </span>\n )}\n {header}\n </div>\n )}\n\n <ul aria-label={ariaLabel} className=\"flex flex-col\">\n {body}\n </ul>\n\n {/* Bulk bar — a dock that floats over the rows rather than a strip that\n pushes them down, so acting on a selection never moves the rows you\n are selecting. Sticky, so it rides the bottom of the scroll area. */}\n {selectable && selectedItems.length > 0 && (\n <div className=\"pointer-events-none sticky bottom-0 z-10 flex justify-center px-5 pb-4\">\n <div className=\"pointer-events-auto flex items-center gap-1.5 rounded-lg bg-accent py-1.5 pl-3.5 pr-1.5 text-accent-fg shadow-overlay\">\n <span className=\"text-sm font-medium\">\n {selectedItems.length} geselecteerd\n </span>\n <span aria-hidden className=\"mx-1.5 h-4 w-px bg-current opacity-25\" />\n {bulkActions}\n <span aria-hidden className=\"mx-1.5 h-4 w-px bg-current opacity-25\" />\n <button\n type=\"button\"\n onClick={() => onSelectionChange?.([])}\n aria-label=\"Selectie wissen\"\n className=\"grid size-tile-md shrink-0 cursor-pointer place-items-center rounded-md transition-colors duration-fast ease-out hover:bg-white/15 focus-visible:outline-none focus-visible:focus-ring\"\n >\n <X className=\"size-icon-lg\" />\n </button>\n </div>\n </div>\n )}\n </div>\n );\n}\n","import React from \"react\";\nimport { cn } from \"../utils/cn\";\n\nexport interface MessageBubbleProps {\n /** Direction. `in` is received, `out` is sent by us. */\n side: \"in\" | \"out\";\n /**\n * Part of a run from the same sender. The bubble keeps its shape; callers use\n * this to drop the repeated header and avatar.\n */\n continued?: boolean;\n /**\n * `warning` for a message that is not settled yet, e.g. a pending draft.\n * `note` is the internal-note surface — amber, never customer-visible.\n */\n tone?: \"default\" | \"warning\" | \"note\";\n /**\n * Layout only — padding, flex behaviour, margins.\n *\n * Not width: the bubble caps its own, because `cn` is plain clsx with no\n * tailwind-merge, so a `max-w-*` passed here would not reliably beat the\n * default — both land in the class list and CSS order decides. A message\n * that runs the full width of the thread stops reading as a message.\n */\n className?: string;\n children: React.ReactNode;\n}\n\n/**\n * A single message in a conversation: chat, email and call transcript all use\n * the same shape.\n *\n * The corner facing the sender is tight (`rounded-sm`) and the other three are\n * `rounded-lg`, which is what makes direction readable without a tail. Sent\n * messages sit on `bg-bubble-out-soft`, a 4% ink wash — deliberately lighter than\n * `accent-soft`, which reads as heavy on every message you have ever sent.\n *\n * @example\n * ```tsx\n * <MessageBubble side=\"out\" className=\"max-w-bubble px-4 py-3\">\n * <Text>{body}</Text>\n * </MessageBubble>\n * ```\n */\nexport function MessageBubble({\n side,\n continued = false,\n tone = \"default\",\n className,\n children,\n}: MessageBubbleProps) {\n return (\n <div\n className={cn(\n // A bubble never spans the whole column; it narrows further from md,\n // where the thread itself is wide enough for the difference to matter.\n // No shadow: a bubble is an inner card, and inner cards separate\n // themselves with a fill. The shadow was doing the separating while both\n // sides were white.\n \"min-w-0 max-w-bubble md:max-w-bubble-md\",\n // No outline on an ordinary message: its fill already separates it from\n // the thread, and a border on every bubble turns a conversation into a\n // stack of boxes. The flagged tones keep theirs — there the outline is\n // the signal, not decoration.\n // tone === \"warning\" && \"border border-warning-border\",\n // tone === \"note\" && \"border border-note-border\",\n // The tight corner points back at the sender.\n side === \"out\" ? \"rounded-lg rounded-tr-sm\" : \"rounded-lg rounded-tl-sm\",\n // Sent is a pale blue, received the neutral sunk grey — the same pair the\n // full-width feed cards use, so a chat thread and a mail thread say\n // \"ours\" and \"theirs\" the same way. Both used to be white on white,\n // which left the corner radius as the only cue.\n tone === \"note\"\n ? \"bg-note-soft\"\n : side === \"out\"\n ? \"bg-bubble-out-soft\"\n : \"bg-surface-sunk\",\n continued && \"mt-1\",\n className\n )}\n >\n {children}\n </div>\n );\n}\n","import React from \"react\";\nimport { cn } from \"../utils/cn\";\n\nexport interface KpiCardProps extends React.HTMLAttributes<HTMLDivElement> {\n /** The big number / metric. */\n value: React.ReactNode;\n /** Caption under the value. */\n label: React.ReactNode;\n /** Tone — `urgent` tints the number + border, `success` tints the number. */\n tone?: \"default\" | \"urgent\" | \"success\";\n}\n\nconst valueTone: Record<NonNullable<KpiCardProps[\"tone\"]>, string> = {\n default: \"text-text\",\n urgent: \"text-danger-fg\",\n success: \"text-success-fg\",\n};\n\n/**\n * KPI / stat card (the Mijn dag metric row). Token-driven, mode-aware.\n *\n * @example\n * ```tsx\n * <KpiCard value={3} label=\"wachten op jou · gem. 1u12\" />\n * <KpiCard value={1} label=\"dreigt SLA te missen\" tone=\"urgent\" />\n * ```\n */\nexport function KpiCard({ value, label, tone = \"default\", className, ...props }: KpiCardProps) {\n return (\n <div className={cn(\"rounded-xl bg-editor px-4 py-3.5\", className)} {...props}>\n <div className={cn(\"text-2xl font-semibold\", valueTone[tone])}>{value}</div>\n <div className=\"pt-0.5 text-xs text-text-muted\">{label}</div>\n </div>\n );\n}\n","import { ChevronLeft, Pencil } from \"lucide-react\";\nimport React, { useEffect, useRef, useState } from \"react\";\nimport { Button, type ButtonProps } from \"../action/Button\";\nimport { SplitButton, type SplitButtonOption } from \"../action/SplitButton\";\nimport { cn } from \"../utils/cn\";\nimport { Icon } from \"./Icon\";\n\nexport interface PageHeaderAction {\n /** Action identifier */\n id: string;\n /** Action label */\n label: string;\n /** Action icon */\n icon?: React.ReactNode;\n /** Action handler */\n onClick: () => void;\n /** Action variant. Tracks Button, so the two cannot drift apart. */\n variant?: ButtonProps[\"variant\"];\n /** Whether action is disabled */\n disabled?: boolean;\n /** Dropdown options for split button */\n splitOptions?: SplitButtonOption[];\n /**\n * Render this action yourself instead of as a Button — a filter chip, a\n * segmented toggle, an avatar stack. Position follows the array, so put it\n * before the buttons to have it sit to their left. When set, every other\n * field except `id` is ignored.\n */\n render?: () => React.ReactNode;\n}\n\nexport interface PageHeaderProps {\n /**\n * `plain` sits directly on the page. `surface` is the app-bar treatment:\n * its own background, full-bleed, closed off with a bottom border.\n */\n surface?: boolean;\n /** Page title */\n title: string;\n /** Page subtitle/description. Sits beside the title. */\n subtitle?: string;\n /**\n * Meta line under the title — a contact, a channel, a timestamp. Distinct\n * from `subtitle`, which sits beside the title, and from `children`, which\n * is the full-width row at the bottom of the header.\n *\n * A string is kept to one line and ellipsised; a node is allowed to wrap, so\n * an inline row of properties survives a narrow window.\n */\n meta?: React.ReactNode;\n /** Breadcrumb items */\n breadcrumbs?: Array<{ label: string; href?: string }>;\n /** Action buttons */\n actions?: PageHeaderAction[];\n /** Additional content to render in the header */\n children?: React.ReactNode;\n /** Additional CSS classes */\n className?: string;\n /** Back button label */\n backLabel?: string;\n /** Back button handler */\n onBack?: () => void;\n /** Back button class name */\n backClassName?: string;\n /** Whether the title is editable */\n editable?: boolean;\n /** Callback when title is changed */\n onTitleChange?: (newTitle: string) => void;\n}\n\nexport const ChevronLeftIcon = () => <Icon icon={ChevronLeft} size=\"md\" color=\"current\" />;\n\n/**\n * PageHeader component for consistent page layouts with title, actions, and breadcrumbs\n */\nexport const PageHeader: React.FC<PageHeaderProps> = ({\n surface = false,\n title,\n subtitle,\n meta,\n actions = [],\n children,\n className,\n backLabel = \"Back\",\n backClassName,\n onBack,\n editable = false,\n onTitleChange,\n}) => {\n const [isEditing, setIsEditing] = useState(false);\n const [editValue, setEditValue] = useState(title);\n const inputRef = useRef<HTMLInputElement>(null);\n\n // Update editValue when title prop changes\n useEffect(() => {\n setEditValue(title);\n }, [title]);\n\n // Focus input when editing starts\n useEffect(() => {\n if (isEditing && inputRef.current) {\n inputRef.current.focus();\n inputRef.current.select();\n }\n }, [isEditing]);\n\n const handleTitleClick = () => {\n if (editable) {\n setIsEditing(true);\n }\n };\n\n const handleBlur = () => {\n setIsEditing(false);\n if (editValue.trim() !== \"\" && editValue !== title && onTitleChange) {\n onTitleChange(editValue.trim());\n } else {\n // Reset to original title if empty or unchanged\n setEditValue(title);\n }\n };\n\n const handleKeyDown = (e: React.KeyboardEvent<HTMLInputElement>) => {\n if (e.key === \"Enter\") {\n inputRef.current?.blur();\n } else if (e.key === \"Escape\") {\n setEditValue(title);\n setIsEditing(false);\n }\n };\n\n return (\n <div\n className={cn(\n \"px-5 pt-4 pb-2.5\",\n // Inside the content card the header shares the card's surface; the\n // rule is the only thing that still closes it off. `surface` therefore\n // only draws the rule — the background it used to paint is now the\n // card itself.\n surface && \"border-b border-border\",\n className\n )}\n >\n {/* Header Title + Actions */}\n <div className=\"flex flex-row sm:items-start sm:justify-between items-center gap-4\">\n {/* Title + Subtitle */}\n <div className=\"min-w-0 flex-1\">\n {/* Back sits beside the title block, not above the meta line, so the\n meta line starts under the title rather than under the button. */}\n <div className=\"flex items-start gap-4 text-text\">\n {onBack && (\n // Ghost: a framed box around a back chevron makes the way out of a\n // page look like the page's primary control.\n <Button variant=\"ghost\" onClick={onBack} leftIcon={<Icon icon={ChevronLeft} size=\"md\" />} iconOnly />\n )}\n\n <div className=\"min-w-0 flex-1\">\n {isEditing ? (\n <input\n ref={inputRef}\n type=\"text\"\n value={editValue}\n onChange={(e) => setEditValue(e.target.value)}\n onBlur={handleBlur}\n onKeyDown={handleKeyDown}\n className=\"text-1xl font-semibold bg-transparent border-b-1 border-border rounded-lg outline-none focus:border-none px-1 -mx-1 min-w-0 w-full\"\n />\n ) : (\n <div className=\"group flex items-baseline gap-2.5 min-w-0\">\n <h2\n onClick={handleTitleClick}\n className={cn(\n \"text-lg font-semibold tracking-title truncate\",\n editable && \"cursor-pointer\"\n )}\n title={editable ? \"Click to edit\" : undefined}\n >\n {title}\n </h2>\n {subtitle && (\n <span className=\"shrink-0 text-base text-text-muted truncate\">{subtitle}</span>\n )}\n {editable && (\n <Pencil\n size={15}\n onClick={handleTitleClick}\n className=\"shrink-0 cursor-pointer text-text-muted opacity-0 group-hover:opacity-100 transition-opacity\"\n />\n )}\n </div>\n )}\n\n {meta && (\n // A string meta is one line and ellipsises; a node may be a row\n // of controls (the interaction header's property line) that has\n // to be allowed to wrap — `truncate` would clip it to one line\n // and hide the last properties.\n <div\n className={cn(\n \"mt-1 min-w-0 text-sm text-text-subtle\",\n typeof meta === \"string\" && \"truncate\",\n )}\n >\n {meta}\n </div>\n )}\n </div>\n </div>\n </div>\n\n {/* Actions */}\n {actions.length > 0 && (\n <div className=\"flex flex-wrap sm:flex-nowrap gap-2 sm:gap-3\">\n {actions.map((action) =>\n action.render ? (\n <React.Fragment key={action.id}>{action.render()}</React.Fragment>\n ) : action.splitOptions && action.splitOptions.length > 0 ? (\n <SplitButton\n key={action.id}\n label={action.label}\n onClick={action.onClick}\n icon={action.icon}\n variant={action.variant === \"primary\" ? \"primary\" : \"outline\"}\n options={action.splitOptions}\n disabled={action.disabled}\n />\n ) : (\n <Button\n key={action.id}\n variant={action.variant ?? \"secondary\"}\n onClick={(e) => {\n e.stopPropagation();\n (e.target as HTMLButtonElement).blur();\n action.onClick();\n }}\n disabled={action.disabled}\n leftIcon={action.icon}\n >\n {action.label}\n </Button>\n )\n )}\n </div>\n )}\n </div>\n\n {/* Custom Slot Content */}\n {children && <div className=\"mt-4\">{children}</div>}\n </div>\n );\n};\n","import React, { type ReactNode } from \"react\";\nimport { ContentLoading, type ContentLoadingShape } from \"../feedback/ContentLoading\";\nimport { cn } from \"../utils/cn\";\nimport { PageHeader, type PageHeaderAction } from \"./PageHeader\";\n\n/**\n * The `md` gutter matches `PageHeader`'s own horizontal padding, so the table\n * or form below lines up with the title above it. The top value is small\n * because the header already supplies most of that gap (`pt-4 pb-2.5`).\n */\nconst paddingClasses = {\n none: \"\",\n sm: \"px-3 pb-3 pt-1\",\n md: \"px-5 pb-5 pt-1.5\",\n} as const;\n\nexport interface PageProps {\n /** Page title, rendered by `PageHeader`. */\n title: string;\n /** Short description beside the title. */\n subtitle?: string;\n /** Line under the title — a count, a record, a timestamp. */\n meta?: ReactNode;\n /** Toolbar actions, right-aligned in the header. */\n actions?: PageHeaderAction[];\n /** Renders the back chevron beside the title. */\n onBack?: () => void;\n /**\n * Lets the user rename the record from the header: the title becomes\n * clickable and grows a pencil beside it. `PageHeader` has had this for a\n * while; `Page` simply never forwarded it, so any page built on `Page` had to\n * put a rename somewhere else.\n */\n editable?: boolean;\n /** Called with the trimmed new title. Only fires when it actually changed. */\n onTitleChange?: (title: string) => void;\n /**\n * Draws the rule under the header. Off by default: inside the content card\n * the header shares the card's surface, and the card's own edge already ends\n * the page — a second line right under the title reads as a divider between\n * two panes that are not there.\n *\n * Turn it on for a header that has to stay legible over content moving\n * underneath it: a dense grid, a feed, anything where the first row would\n * otherwise scroll up flush against the title.\n */\n surface?: boolean;\n /** Full-width row at the bottom of the header — a filter strip, a tab bar. */\n headerContent?: ReactNode;\n /** Swaps the body for a skeleton. */\n loading?: boolean;\n /**\n * What the body is about to render, so the placeholder has the right shape.\n * Most app pages are a table; a detail page is usually a form.\n */\n loadingShape?: ContentLoadingShape;\n /**\n * Rendered instead of `children` when there is nothing to show — pass an\n * `EmptyState`. Ignored while `loading`, so an empty list does not flash its\n * \"nothing here\" message during the first fetch.\n */\n empty?: ReactNode;\n padding?: keyof typeof paddingClasses;\n /**\n * Whether the page owns its scroll. `true` (default) pins the header and\n * scrolls the body — the right behaviour for a table you page through.\n * Set `false` when the page is rendered inside something that already\n * scrolls and should flow with it.\n */\n scroll?: boolean;\n className?: string;\n contentClassName?: string;\n children?: ReactNode;\n}\n\n/**\n * One app page: the header, the content gutter, the scroll container, and the\n * loading and empty states.\n *\n * These four were re-invented per page — 24 times in `eylo-voip` alone, each\n * with its own gutter — which is how `p-4` there and `px-5` everywhere else\n * ended up side by side in the same product. Reach for this instead of pairing\n * a `PageHeader` with a padded `div`.\n *\n * Settings panels are the exception: they live inside the settings frame, which\n * draws its own title and scrolls itself, so they use `SettingsPage`.\n *\n * @example\n * ```tsx\n * <Page\n * title={t(\"interactions\")}\n * subtitle={t(\"interactions_description\")}\n * actions={[{ id: \"refresh\", label: t(\"refresh\"), onClick: reload }]}\n * loading={loading}\n * empty={!interactions.length && <EmptyState title={t(\"interaction_no_records_found\")} />}\n * >\n * <InteractionsTable interactions={interactions} />\n * </Page>\n * ```\n */\nexport const Page: React.FC<PageProps> = ({\n title,\n subtitle,\n meta,\n actions,\n onBack,\n editable,\n onTitleChange,\n surface = false,\n headerContent,\n loading = false,\n loadingShape = \"table\",\n empty,\n padding = \"md\",\n scroll = true,\n className,\n contentClassName,\n children,\n}) => {\n const body = loading ? (\n <ContentLoading variant=\"inline\" shape={loadingShape} />\n ) : empty ? (\n <div className=\"flex flex-col items-center justify-center py-12\">{empty}</div>\n ) : (\n children\n );\n\n return (\n <div\n className={cn(\n // `h-full` resolves against the shell's content card, which is the\n // element that scrolls today. Taking the scroll over here is what pins\n // the header; without `min-h-0` the body would grow past the card\n // instead of scrolling inside it.\n scroll ? \"flex h-full min-h-0 flex-col\" : \"flex flex-col\",\n className,\n )}\n >\n <PageHeader\n surface={surface}\n title={title}\n subtitle={subtitle}\n meta={meta}\n actions={actions}\n onBack={onBack}\n editable={editable}\n onTitleChange={onTitleChange}\n className={scroll ? \"shrink-0\" : undefined}\n >\n {headerContent}\n </PageHeader>\n\n <div\n className={cn(\n scroll && \"min-h-0 flex-1 overflow-y-auto\",\n paddingClasses[padding],\n contentClassName,\n )}\n >\n {body}\n </div>\n </div>\n );\n};\n","import React from \"react\";\nimport { cn } from \"../utils/cn\";\n\nexport interface SectionCaptionProps {\n /** Uppercase label. Short — this is a caption, not a heading. */\n label: string;\n /**\n * The right-hand slot: a count, a progress (\"1/3 done\") or a summary\n * (\"2 on a call · 1 away\"). A caption with nothing to its right is a caption\n * that could have been a heading.\n */\n meta?: string;\n /** Far right — a toggle or an icon button. Sits after `meta` when both are set. */\n action?: React.ReactNode;\n /** Layout only (margins, alignment). Not padding: see the note below. */\n className?: string;\n}\n\n/**\n * The section header over rounded plates and cards — the counterpart of the\n * sticky sunk band, which belongs to full-bleed divided rows.\n *\n * The top padding is generous and self-cancelling (`pt-7 first:pt-0`): a caption\n * is what separates two blocks in a scrolling panel, so it carries the gap\n * rather than the blocks around it, and the first one in a panel does not push\n * the content away from the panel header.\n *\n * `className` cannot override that padding — `cn` is plain clsx with no\n * tailwind-merge, so both classes would land in the list and CSS order would\n * decide. Use it for margins and alignment only.\n */\nexport const SectionCaption: React.FC<SectionCaptionProps> = ({ label, meta, action, className }) => (\n <div className={cn(\"flex items-center gap-2 px-1 pb-2 pt-7 first:pt-0\", className)}>\n <span className=\"shrink-0 text-2xs font-semibold uppercase tracking-label text-text-subtle\">{label}</span>\n {meta && (\n <span className=\"min-w-0 flex-1 truncate text-right text-xs tabular-nums text-text-subtle\">{meta}</span>\n )}\n {action && <span className=\"ml-auto shrink-0\">{action}</span>}\n </div>\n);\n","import React from \"react\";\nimport { cn } from \"../utils/cn\";\n\nexport interface SectionDividerProps {\n /** Centred label. Without one the divider is a plain rule. */\n label?: React.ReactNode;\n /** Right-aligned slot after the rule, e.g. a count or a status. */\n trailing?: React.ReactNode;\n /** Push the label to the start instead of centring it. */\n align?: \"center\" | \"start\";\n className?: string;\n}\n\n/**\n * A hairline that separates two runs of content, optionally naming the run that\n * follows: day separators in a feed, group headings in search results.\n *\n * @example\n * ```tsx\n * <SectionDivider label=\"Gisteren\" />\n * <SectionDivider label=\"Gesprekken\" align=\"start\" trailing={<Badge>12</Badge>} />\n * ```\n */\nexport function SectionDivider({ label, trailing, align = \"center\", className }: SectionDividerProps) {\n const rule = <span className=\"h-px flex-1 bg-border-subtle\" aria-hidden />;\n\n if (!label && !trailing) {\n return <div className={cn(\"flex items-center py-2\", className)}>{rule}</div>;\n }\n\n return (\n <div className={cn(\"flex items-center gap-3 py-2\", className)}>\n {align === \"center\" && rule}\n <span className=\"shrink-0 text-xs font-medium text-text-muted\">{label}</span>\n {rule}\n {trailing && <span className=\"shrink-0\">{trailing}</span>}\n </div>\n );\n}\n","import { ChevronLeft } from \"lucide-react\";\nimport React, {\n createContext,\n useContext,\n useEffect,\n useId,\n useMemo,\n useRef,\n useState,\n type ReactNode,\n} from \"react\";\nimport { Button } from \"../action/Button\";\nimport { ContentLoading, type ContentLoadingShape } from \"../feedback/ContentLoading\";\nimport { cn } from \"../utils/cn\";\nimport { Icon } from \"./Icon\";\nimport type { PageHeaderAction } from \"./PageHeader\";\nimport { PageToolbarActions } from \"./PageToolbar\";\n\n/**\n * What a panel adds to the frame it is rendered in: the record it drilled into,\n * and the way back out. The settings frame already draws the app breadcrumb and\n * the page title, so a panel that repeats them produces the double bar this\n * component exists to remove.\n */\nexport interface SettingsTrailEntry {\n /** Appended to the frame breadcrumb; usually the detail record's name. */\n title?: string;\n /** When set, the frame renders the back affordance and calls this. */\n onBack?: () => void;\n}\n\nexport interface SettingsFrameApi {\n /**\n * `ownerId` scopes the write to one panel instance. Stable across renders,\n * so it is safe to use as a hook dependency.\n */\n setTrail: (ownerId: string, entry: SettingsTrailEntry | null) => void;\n}\n\nconst SettingsFrameContext = createContext<SettingsFrameApi | null>(null);\n\n/**\n * Provided by the settings frame (the shell overlay), consumed by panels that\n * are federated remotes. Safe across the module-federation boundary because\n * React and `@opencxh/ui-kit` are both shared singletons — a second copy of\n * either would hand panels a different context object and the trail would\n * silently never arrive.\n */\nexport const SettingsFrameProvider = SettingsFrameContext.Provider;\n\nexport function useSettingsFrame(): SettingsFrameApi | null {\n return useContext(SettingsFrameContext);\n}\n\n/**\n * State half of the frame contract, for the host to own. Returns the current\n * trail plus the stable api to hand down through `SettingsFrameProvider`.\n */\nexport function useSettingsFrameHost() {\n const [state, setState] = useState<{ ownerId: string; entry: SettingsTrailEntry } | null>(null);\n\n const api = useMemo<SettingsFrameApi>(\n () => ({\n setTrail: (ownerId, entry) =>\n setState((prev) => {\n if (entry) return { ownerId, entry };\n // A panel that unmounts *after* its replacement has already mounted\n // must not wipe the replacement's trail. Only the current owner is\n // allowed to clear.\n return prev && prev.ownerId !== ownerId ? prev : null;\n }),\n }),\n []\n );\n\n return { trail: state?.entry ?? null, api };\n}\n\nconst paddingClasses = {\n none: \"\",\n sm: \"px-3 py-3\",\n // Matches the frame header's own horizontal padding, so content lines up\n // with the title above it.\n md: \"px-5 py-4\",\n} as const;\n\nexport interface SettingsPageProps {\n children: ReactNode;\n /**\n * Primary actions, right-aligned in the sticky footer — the Cancel/Save pair\n * of a form. Omit entirely on a read-only or list page and no footer renders.\n */\n actions?: PageHeaderAction[];\n /** Left-aligned footer actions, set apart from the primary pair (e.g. Delete). */\n secondaryActions?: PageHeaderAction[];\n /** Renders the back affordance in the frame header (or inline when unframed). */\n onBack?: () => void;\n backLabel?: string;\n /** The record's own name, appended to the frame breadcrumb. */\n title?: string;\n /** Swaps the body for a skeleton while keeping the footer in place. */\n loading?: boolean;\n /**\n * What the body is about to render. A settings panel is nearly always a form\n * or a table, and saying which keeps the placeholder from announcing a\n * heading and two paragraphs that never arrive.\n */\n loadingShape?: ContentLoadingShape;\n padding?: keyof typeof paddingClasses;\n className?: string;\n contentClassName?: string;\n}\n\n/**\n * The body of one settings panel. Owns the three things every panel used to\n * re-invent: the scroll container, the content padding, and where the actions\n * live. Title, description and breadcrumb belong to the frame — pass `title`\n * and `onBack` to extend them rather than drawing a second header here.\n */\nexport const SettingsPage: React.FC<SettingsPageProps> = ({\n children,\n actions = [],\n secondaryActions = [],\n onBack,\n backLabel = \"Back\",\n title,\n loading = false,\n loadingShape = \"form\",\n padding = \"md\",\n className,\n contentClassName,\n}) => {\n const frame = useSettingsFrame();\n const ownerId = useId();\n\n // The handler is re-created on every render of the panel; keeping it in a ref\n // means the effect below depends on *whether* there is a back action, not on\n // its identity — otherwise every render would re-publish the trail and the\n // resulting frame re-render would loop.\n const backRef = useRef(onBack);\n backRef.current = onBack;\n\n const hasBack = Boolean(onBack);\n\n useEffect(() => {\n if (!frame) return;\n if (!hasBack && !title) return;\n frame.setTrail(ownerId, {\n title,\n onBack: hasBack ? () => backRef.current?.() : undefined,\n });\n return () => frame.setTrail(ownerId, null);\n }, [frame, ownerId, title, hasBack]);\n\n const showFooter = actions.length > 0 || secondaryActions.length > 0;\n\n return (\n /**\n * `min-h-full` + a sticky footer, rather than a nested scroll container.\n * The frame already scrolls, and taking that over here would clip every\n * panel that has not been migrated yet. This way a short page still drops\n * its footer to the bottom, and a long one keeps it pinned while scrolling.\n */\n <div className={cn(\"flex min-h-full flex-col\", className)}>\n {/**\n * Unframed usage — the same panel opened as a modal or a plain route.\n * There is no frame to hand the title and the back action to, so this\n * draws them itself. Without this the record's name simply disappears\n * outside the settings overlay.\n */}\n {!frame && (hasBack || title) && (\n <div className=\"flex shrink-0 items-center gap-2 px-5 pt-4\">\n {hasBack && (\n <Button\n variant=\"ghost\"\n onClick={() => backRef.current?.()}\n aria-label={backLabel}\n leftIcon={<Icon icon={ChevronLeft} size=\"sm\" />}\n iconOnly\n />\n )}\n {title && (\n <h2 className=\"min-w-0 truncate text-md font-semibold tracking-title text-text\">\n {title}\n </h2>\n )}\n </div>\n )}\n\n <div className={cn(\"flex-1\", paddingClasses[padding], contentClassName)}>\n {loading ? <ContentLoading variant=\"inline\" shape={loadingShape} /> : children}\n </div>\n\n {showFooter && (\n <div className=\"sticky bottom-0 z-10 flex shrink-0 items-center gap-2 border-t border-border bg-surface px-5 py-3\">\n {secondaryActions.length > 0 && (\n <PageToolbarActions actions={secondaryActions} defaultVariant=\"ghost\" />\n )}\n {actions.length > 0 && (\n <PageToolbarActions actions={actions} className=\"ml-auto\" />\n )}\n </div>\n )}\n </div>\n );\n};\n","import React from \"react\";\nimport { cn } from \"../utils/cn\";\nimport { Icon } from \"./Icon\";\n\nexport interface SettingsRowProps {\n /** What the setting is called. */\n label: React.ReactNode;\n /** One line on what it does or what turning it on means. */\n description?: React.ReactNode;\n /** The control itself — a `Switch`, `Select`, `Button`… */\n control: React.ReactNode;\n /**\n * Draw the row as a bordered pill. Use it for a flat list of independent\n * toggles; leave it off inside a `SettingsSection`, which already groups.\n */\n bordered?: boolean;\n disabled?: boolean;\n className?: string;\n}\n\n/**\n * One setting: label (+ description) on the left, its control on the right.\n *\n * @example\n * ```tsx\n * <SettingsRow\n * label=\"Agenda synchroniseren\"\n * description=\"Afspraken uit dit account verschijnen in je agenda.\"\n * control={<Switch checked={on} onChange={setOn} aria-label=\"Agenda synchroniseren\" />}\n * />\n * ```\n */\nexport function SettingsRow({\n label,\n description,\n control,\n bordered = false,\n disabled = false,\n className,\n}: SettingsRowProps) {\n return (\n <div\n className={cn(\n \"flex items-center justify-between gap-4 py-2\",\n bordered && \"rounded-lg border border-border px-3\",\n disabled && \"opacity-50\",\n className\n )}\n >\n <div className=\"min-w-0\">\n <div className=\"text-sm text-text\">{label}</div>\n {description && (\n <div className=\"text-xs text-text-muted\">{description}</div>\n )}\n </div>\n <div className=\"shrink-0\">{control}</div>\n </div>\n );\n}\n\nexport interface SettingsSectionProps {\n /** Lucide icon component, rendered in the section heading. */\n icon?: React.ComponentType<Record<string, unknown>>;\n title: React.ReactNode;\n description?: React.ReactNode;\n /** Right-aligned slot in the heading, e.g. a \"Reset\" button. */\n actions?: React.ReactNode;\n children: React.ReactNode;\n className?: string;\n}\n\n/**\n * A titled group of `SettingsRow`s. The body is indented to line up under the\n * title text rather than the icon.\n */\nexport function SettingsSection({\n icon,\n title,\n description,\n actions,\n children,\n className,\n}: SettingsSectionProps) {\n return (\n <section className={cn(\"flex flex-col gap-2\", className)}>\n <div className=\"flex items-start gap-2\">\n {icon && <Icon icon={icon} size=\"md\" color=\"secondary\" className=\"mt-0.5\" />}\n <div className=\"min-w-0 flex-1\">\n <h3 className=\"text-sm font-semibold text-text\">{title}</h3>\n {description && (\n <p className=\"text-xs text-text-muted\">{description}</p>\n )}\n </div>\n {actions && <div className=\"shrink-0\">{actions}</div>}\n </div>\n <div className={cn(\"flex flex-col\", icon && \"pl-6\")}>{children}</div>\n </section>\n );\n}\n","import React from \"react\";\nimport { ArrowUpRight } from \"lucide-react\";\nimport { cn } from \"../utils/cn\";\nimport { Icon } from \"./Icon\";\n\nexport interface SourceChipProps {\n /** Label — the linked conversation subject. */\n label: React.ReactNode;\n /** Optional leading dot colour (a `--color-cat-*` or channel CSS var). */\n dotColor?: string;\n /** Click opens the linked conversation. */\n onClick?: () => void;\n className?: string;\n}\n\n/**\n * Source-conversation chip — the \"open brongesprek / gekoppeld gesprek ↗\" pill\n * that links a task or focus item back to its conversation.\n *\n * @example\n * ```tsx\n * <SourceChip label=\"Vraag over factuur maart\" dotColor=\"var(--color-cat-2)\" onClick={openThread} />\n * ```\n */\nexport function SourceChip({ label, dotColor, onClick, className }: SourceChipProps) {\n return (\n <button\n type=\"button\"\n onClick={onClick}\n className={cn(\n \"inline-flex max-w-full items-center gap-1.5 rounded-full bg-surface-sunk px-2.5 py-1 text-xs text-text-muted transition-colors duration-fast ease-out hover:bg-surface-hover hover:text-text\",\n className,\n )}\n >\n {dotColor && (\n <span className=\"h-1.5 w-1.5 shrink-0 rounded-full\" style={{ backgroundColor: dotColor }} aria-hidden />\n )}\n <span className=\"min-w-0 truncate\">{label}</span>\n <Icon icon={ArrowUpRight} size=\"xs\" className=\"opacity-70\" />\n </button>\n );\n}\n","import React from \"react\";\nimport { Badge, type BadgeProps } from \"../feedback/Badge\";\nimport type { TableColumn } from \"./Table\";\n\n/**\n * Column builders for the three things table configs kept getting wrong, each\n * in the same way across apps: a state rendered as prose, a stored code shown\n * raw, and an id shown instead of the name it points at.\n *\n * They all keep the *label* in `accessor` and render only the decoration in\n * `cell`, because `Table` searches and sorts on the accessor value. Putting the\n * readable text there means a search for \"Active\" or for a team's name matches\n * what the row actually shows — which is exactly what a raw `enabled` boolean\n * or a bare `teamId` used to break.\n */\n\nexport interface BadgeColumnConfig<T, V = unknown> {\n id: string;\n header: string;\n accessor: (row: T) => V;\n /** The text in the badge — and the text this column is searched on. */\n label: (value: V, row: T) => string;\n /** Defaults to `default`; give states their own tone (success/error/…). */\n tone?: (value: V, row: T) => BadgeProps[\"variant\"];\n /** Return false to render nothing at all for this row. */\n visible?: (value: V, row: T) => boolean;\n width?: string | number;\n sortable?: boolean;\n align?: TableColumn<T>[\"align\"];\n}\n\n/** A value that is a state rather than prose — render it as a pill. */\nexport function badgeColumn<T, V = unknown>(\n config: BadgeColumnConfig<T, V>\n): TableColumn<T> {\n const { id, header, accessor, label, tone, visible, width, sortable, align } = config;\n return {\n id,\n header,\n accessor: (row: T) => label(accessor(row), row),\n cell: (_value: unknown, row: T) => {\n const raw = accessor(row);\n if (visible && !visible(raw, row)) return null;\n return (\n <Badge variant={tone ? tone(raw, row) : \"default\"} size=\"sm\">\n {label(raw, row)}\n </Badge>\n );\n },\n width,\n sortable,\n align,\n };\n}\n\nexport interface BooleanBadgeColumnConfig<T> {\n id: string;\n header: string;\n accessor: (row: T) => boolean | undefined;\n onLabel: string;\n offLabel: string;\n /** Defaults to success/secondary — on reads as healthy, off as merely quiet. */\n onTone?: BadgeProps[\"variant\"];\n offTone?: BadgeProps[\"variant\"];\n width?: string | number;\n sortable?: boolean;\n}\n\n/** The on/off case of `badgeColumn`, which is most of them. */\nexport function booleanBadgeColumn<T>(\n config: BooleanBadgeColumnConfig<T>\n): TableColumn<T> {\n const {\n id, header, accessor, onLabel, offLabel,\n onTone = \"success\", offTone = \"secondary\", width, sortable,\n } = config;\n\n return badgeColumn<T, boolean>({\n id,\n header,\n accessor: (row) => !!accessor(row),\n label: (on) => (on ? onLabel : offLabel),\n tone: (on) => (on ? onTone : offTone),\n width,\n sortable,\n });\n}\n\nexport interface LabelsColumnConfig<T> {\n id: string;\n header: string;\n /** One code, a list of them, or nothing. */\n accessor: (row: T) => string | string[] | undefined | null;\n /**\n * Code to readable text. Return `undefined` to fall back to the code itself,\n * so an unknown value still shows something instead of vanishing.\n */\n label: (code: string) => string | undefined;\n /** Shown when there is nothing at all. Defaults to an em dash. */\n empty?: string;\n separator?: string;\n width?: string | number;\n searchable?: boolean;\n sortable?: boolean;\n}\n\n/**\n * Stored codes rendered as the words the user picked them by. Covers both\n * localising an enum (`interactions:created` → \"Interaction created\") and\n * resolving a foreign key (a `teamId` → that team's name — pass a lookup as\n * `label`), because from the table's side those are the same problem.\n */\nexport function labelsColumn<T>(config: LabelsColumnConfig<T>): TableColumn<T> {\n const {\n id, header, accessor, label, empty = \"—\", separator = \", \",\n width, searchable, sortable,\n } = config;\n\n return {\n id,\n header,\n accessor: (row: T) => {\n const raw = accessor(row);\n const codes = raw == null ? [] : Array.isArray(raw) ? raw : [raw];\n const labelled = codes.filter(Boolean).map((code) => label(code) ?? code);\n return labelled.length ? labelled.join(separator) : empty;\n },\n width,\n searchable,\n sortable,\n };\n}\n","import React, { useCallback } from \"react\";\nimport { Text } from \"../typography/Text\";\nimport { cn } from \"../utils/cn\";\n\nexport type ViewFieldType =\n | \"text\"\n | \"email\"\n | \"password\"\n | \"number\"\n | \"tel\"\n | \"url\"\n | \"textarea\"\n | \"select\"\n | \"checkbox\"\n | \"radio\"\n | \"date\"\n | \"custom\"\n | \"array\";\n\ntype NestedKeys<T> = {\n [K in keyof T]: T[K] extends object\n ? `${K & string}.${NestedKeys<T[K]>}`\n : K & string;\n}[keyof T];\n\nfunction getValueByPath<T>(obj: T, path: string): unknown {\n return path\n .split(\".\")\n .reduce(\n (acc, key) =>\n acc && typeof acc === \"object\" && key in acc\n ? (acc as any)[key]\n : undefined,\n obj\n );\n}\n\nexport interface ViewGroupItem<T = any> {\n /** Field name (key in data) */\n name: NestedKeys<T>;\n /** Field label */\n label: string;\n /** Field type */\n type: ViewFieldType;\n /** Field width (CSS width value or grid columns) */\n width?: string | number;\n /** Options for select/radio/checkbox types */\n options?: Array<{\n value: string | number;\n label: string;\n }>;\n /** Conditional function to show/hide field */\n conditional?: (data: T) => boolean;\n /** Whether field is hidden */\n hidden?: boolean;\n /** Custom component renderer */\n customComponent?: (props: { value: any }) => React.ReactNode;\n /** Format function for display value */\n format?: (value: any, data: T) => string | React.ReactNode;\n\n /** For 'array' type, defines the fields for each item in the array */\n arrayFields?: ViewGroupItem<any>[];\n}\n\nexport interface ViewGroup<T = any> {\n /** Group identifier */\n id: string;\n /** Group title */\n title: string;\n /** Group description */\n description?: string;\n /** Group items */\n items: ViewGroupItem<T>[];\n /** Conditional function to show/hide group */\n conditional?: (data: T) => boolean;\n /** Group layout */\n layout?: \"grid\" | \"flex\";\n /** Number of columns for grid layout */\n columns?: number;\n /** Additional CSS classes */\n className?: string;\n}\n\nexport interface ViewProps<T = Record<string, any>> {\n /** View groups */\n groups: ViewGroup<T>[];\n /** Data to display */\n data: T;\n /** View size */\n size?: \"sm\" | \"md\" | \"lg\" | \"full\";\n /** Additional CSS classes */\n className?: string;\n}\n\n/**\n * Generic View component with groups and conditional rendering\n * Displays data in a read-only format matching the Form component layout\n */\nexport const View = <T extends Record<string, any>>({\n groups,\n data,\n size = \"md\",\n className,\n}: ViewProps<T>) => {\n // Format date for display\n const formatDate = (value: any): string => {\n if (!value) return \"-\";\n try {\n const date = new Date(value);\n return date.toLocaleDateString(\"nl-NL\", {\n year: \"numeric\",\n month: \"long\",\n day: \"numeric\",\n });\n } catch {\n return String(value);\n }\n };\n\n // Format checkbox value\n const formatCheckbox = (value: any): string => {\n return value ? \"Ja\" : \"Nee\";\n };\n\n // Get display value for select/radio options\n const getOptionLabel = (\n value: any,\n options?: Array<{ value: string | number; label: string }>\n ): string => {\n if (!options) return String(value || \"-\");\n const option = options.find((opt) => opt.value === value);\n return option ? option.label : String(value || \"-\");\n };\n\n // Render a single field\n const renderField = useCallback(\n (item: ViewGroupItem<T>) => {\n const value = getValueByPath(data, item.name as string);\n\n // Handle array type\n if (item.type === \"array\") {\n const arrayValue = value as any[] | undefined;\n if (!arrayValue || arrayValue.length === 0) {\n return (\n <Text\n variant=\"body\"\n size=\"sm\"\n className=\"text-text-muted\"\n >\n Geen items\n </Text>\n );\n }\n\n return (\n <div className=\"space-y-3\">\n {arrayValue.map((row, index) => (\n <div\n key={index}\n className=\"p-4 border border-border rounded-xl space-y-3\"\n >\n <div className=\"flex items-center justify-between\">\n <Text\n variant=\"label\"\n size=\"sm\"\n weight=\"medium\"\n className=\"text-text-muted\"\n >\n {item.label} {index + 1}\n </Text>\n </div>\n <div className=\"grid grid-cols-1 sm:grid-cols-2 gap-3\">\n {item.arrayFields?.map((subField) => {\n const subValue = row?.[subField.name];\n let displayValue: React.ReactNode = \"-\";\n\n switch (subField.type) {\n case \"text\":\n case \"email\":\n case \"number\":\n case \"tel\":\n case \"url\":\n case \"textarea\":\n displayValue = subValue || \"-\";\n break;\n case \"select\":\n case \"radio\":\n displayValue = getOptionLabel(\n subValue,\n subField.options\n );\n break;\n case \"checkbox\":\n displayValue = formatCheckbox(subValue);\n break;\n case \"date\":\n displayValue = formatDate(subValue);\n break;\n case \"custom\":\n displayValue = subField.customComponent?.({\n value: subValue,\n });\n break;\n default:\n displayValue = String(subValue || \"-\");\n }\n\n if (subField.format) {\n displayValue = subField.format(subValue, row);\n }\n\n return (\n <div key={subField.name as string} className=\"space-y-1\">\n <Text\n variant=\"label\"\n size=\"xs\"\n className=\"text-text-muted\"\n >\n {subField.label}\n </Text>\n <Text\n variant=\"body\"\n size=\"sm\"\n className=\"text-text\"\n >\n {displayValue}\n </Text>\n </div>\n );\n })}\n </div>\n </div>\n ))}\n </div>\n );\n }\n\n // Handle custom component\n if (item.type === \"custom\" && item.customComponent) {\n return item.customComponent({ value });\n }\n\n // Handle format function\n if (item.format) {\n const formatted = item.format(value, data);\n return (\n <Text\n variant=\"body\"\n size=\"sm\"\n className=\"text-text\"\n >\n {formatted}\n </Text>\n );\n }\n\n // Default rendering based on type\n let displayValue: React.ReactNode = \"-\";\n\n switch (item.type) {\n case \"text\":\n case \"email\":\n case \"password\":\n case \"number\":\n case \"tel\":\n case \"url\":\n displayValue = value ? String(value) : \"-\";\n break;\n\n case \"textarea\":\n displayValue = value ? (\n <div className=\"whitespace-pre-wrap\">{String(value || \"-\")}</div>\n ) : (\n \"-\"\n );\n break;\n\n case \"select\":\n case \"radio\":\n displayValue = getOptionLabel(value, item.options);\n break;\n\n case \"checkbox\":\n displayValue = formatCheckbox(value);\n break;\n\n case \"date\":\n displayValue = formatDate(value);\n break;\n\n default:\n displayValue = value ? String(value) : \"-\";\n }\n\n return (\n <Text\n variant=\"body\"\n size=\"sm\"\n className=\"text-text\"\n >\n {displayValue}\n </Text>\n );\n },\n [data]\n );\n\n // Render view group\n const renderGroup = useCallback(\n (group: ViewGroup<T>) => {\n // Check group conditional\n if (group.conditional && !group.conditional(data)) {\n return null;\n }\n\n const visibleItems = group.items.filter((item) => {\n if (item.hidden) return false;\n if (item.conditional && !item.conditional(data)) return false;\n return true;\n });\n\n if (visibleItems.length === 0) return null;\n\n const groupClasses = cn(\n \"space-y-4\",\n {\n \"grid gap-4\": group.layout === \"grid\",\n \"flex flex-wrap gap-4\": group.layout === \"flex\",\n },\n group.layout === \"grid\" && {\n \"grid-cols-1\": !group.columns || group.columns === 1,\n \"grid-cols-2\": group.columns === 2,\n \"grid-cols-3\": group.columns === 3,\n \"grid-cols-4\": group.columns === 4,\n },\n group.className\n );\n\n return (\n <div\n key={group.id}\n className=\"grid grid-cols-1 md:grid-cols-3 gap-8 p-6 border border-border rounded-xl\"\n >\n {/* Group Header */}\n <div className=\"md:col-span-1\">\n <Text\n variant=\"label\"\n size=\"lg\"\n weight=\"semibold\"\n className=\"text-text\"\n >\n {group.title}\n </Text>\n {group.description && (\n <Text\n variant=\"body\"\n size=\"sm\"\n className=\"text-text-muted mt-1\"\n >\n {group.description}\n </Text>\n )}\n </div>\n\n {/* Group Items */}\n <div className=\"md:col-span-2\">\n <div className={groupClasses}>\n {visibleItems.map((item) => {\n return (\n <div\n key={item.name as string}\n className=\"space-y-1\"\n // Inline, not `w-[…]`/`col-span-…`: those are built at runtime,\n // so Tailwind never sees them and `width` silently did nothing.\n // Same fix Form.tsx already carries.\n style={{\n width: typeof item.width === \"string\" ? item.width : undefined,\n gridColumn:\n typeof item.width === \"number\"\n ? `span ${item.width} / span ${item.width}`\n : undefined,\n }}\n >\n {/* Field Label */}\n {item.type !== \"custom\" && (\n <Text\n variant=\"label\"\n size=\"sm\"\n className=\"font-medium text-text-muted\"\n >\n {item.label}\n </Text>\n )}\n\n {/* Field Value */}\n {renderField(item)}\n </div>\n );\n })}\n </div>\n </div>\n </div>\n );\n },\n [data, renderField]\n );\n\n const viewClasses = cn(\n \"space-y-6\",\n {\n \"max-w-md\": size === \"sm\",\n \"max-w-2xl\": size === \"md\",\n \"max-w-4xl\": size === \"lg\",\n \"max-w-full\": size === \"full\",\n },\n className\n );\n\n return (\n <div className={viewClasses}>\n {/* View Groups */}\n <div className=\"space-y-8\">{groups.map(renderGroup)}</div>\n </div>\n );\n};\n","import React from \"react\";\nimport { ContentLoading } from \"../feedback/ContentLoading\";\nimport { cn } from \"../utils/cn\";\n\nexport interface MenuItemAction {\n /** Icoon aan de rechterkant van de rij. */\n icon: React.ReactNode;\n /** Verplicht: aria-label + tooltip, het is een icon-only knop. */\n label: string;\n onClick: () => void;\n /** \"hover\" (default) = alleen zichtbaar bij hover/focus, \"always\" = altijd. */\n visibility?: \"hover\" | \"always\";\n}\n\nexport interface MenuItem {\n icon?: React.ReactNode;\n label: string;\n count?: number;\n /**\n * Optionele actie rechts op de rij — verwijderen, pinnen, dempen. Navigeert\n * niet: de knop stopt propagatie en roept alleen zijn eigen onClick aan.\n */\n action?: MenuItemAction;\n children?: MenuItem[];\n path?: string;\n /**\n * @deprecated Groepen klappen niet meer in — een sectie met children rendert\n * als kop met zijn items eronder. Blijft bestaan zodat bestaande call-sites\n * blijven compileren; de waarde wordt genegeerd.\n */\n defaultCollapsed?: boolean;\n}\n\ninterface SidebarMenuProps {\n items: MenuItem[];\n isSelectedHandler: (path: string | undefined) => boolean;\n onClick?: (path: string | undefined) => void;\n preMenuItemsComponent?: React.ReactNode;\n /**\n * The app that owns this menu has not reported in yet. Draws the menu's own\n * geometry in placeholder form rather than nothing: an empty column during\n * startup reads as \"this app has no menu\", and the items then appear and shove\n * the first click target somewhere else.\n */\n loading?: boolean;\n}\n\n/**\n * Placeholder in the shape of the menu: a caption, then rows at item height.\n * The geometry lives in `ContentLoading`'s `menu` shape so there is one menu\n * placeholder in the product rather than a copy per column that renders one.\n */\nconst SidebarMenuSkeleton: React.FC = () => (\n <ContentLoading variant=\"inline\" shape=\"menu\" />\n);\n\ntype SelectedHandler = (path: string | undefined) => boolean;\ntype ClickHandler = (path: string | undefined) => void;\n\nconst SidebarMenuItem: React.FC<{\n item: MenuItem;\n isSelectedHandler: SelectedHandler;\n onClick?: ClickHandler;\n depth?: number;\n}> = ({ item, isSelectedHandler, onClick, depth = 0 }) => {\n const hasChildren = Boolean(item.children && item.children.length > 0);\n const isSelected = isSelectedHandler ? isSelectedHandler(item.path) : false;\n\n // Een item met children is een sectie, geen bestemming: geen hover, geen\n // cursor, geen selectie — alleen een kop boven zijn items.\n if (hasChildren) {\n return (\n <li>\n {/* Een sectie zonder naam krijgt geen kop. Anders bleef er een lege\n regel met `pt-5 pb-2` boven de items staan: witruimte die belooft\n dat er een groep begint, zonder te zeggen welke. */}\n {item.label && (\n <div\n className={cn(\n \"flex items-center gap-2 px-2.5 pt-5 pb-2 text-2xs font-semibold uppercase tracking-label text-text-disabled\",\n )}\n >\n <span className=\"min-w-0 flex-1 truncate\">{item.label}</span>\n {item.count !== undefined && item.count > 0 && (\n <span className=\"font-normal tabular-nums\">{item.count}</span>\n )}\n </div>\n )}\n <ul className=\"flex flex-col gap-px\">\n {item.children?.map((child, index) => (\n <SidebarMenuItem\n key={index}\n item={child}\n isSelectedHandler={isSelectedHandler}\n onClick={onClick}\n depth={depth + 1}\n />\n ))}\n </ul>\n </li>\n );\n }\n\n // Een hover-actie wisselt de count af in plaats van ernaast te schuiven,\n // anders verspringt de rij zodra de muis erop komt.\n const action = item.action;\n const swapsWithCount = action?.visibility !== \"always\";\n\n return (\n <li>\n <div\n role=\"button\"\n tabIndex={0}\n onClick={() => item.path && onClick?.(item.path)}\n onKeyDown={(e) => {\n if (e.key === \"Enter\" || e.key === \" \") {\n e.preventDefault();\n item.path && onClick?.(item.path);\n }\n }}\n className={cn(\n // De kolom ligt op de backdrop, niet op een paneel: het actieve item\n // is daarom een opliggende witte plaat, en de hover is de backdrop-\n // hover (donkerder) in plaats van de surface-hover (lichter).\n \"group/item flex h-row-md cursor-pointer items-center gap-2.5 rounded-md px-2.5 text-base no-underline\",\n \"transition-colors duration-fast ease-out\",\n \"focus-visible:outline-none focus-visible:focus-ring\",\n isSelected\n // `surface-hover`, not pure white: on the 0.93 backdrop a #fff plate\n // is a 7% jump and the current item shouts. Still a raised plate —\n // same language as the rail and the segmented toggle — just quieter.\n ? \"bg-surface-hover font-medium text-text shadow-sm\"\n : \"text-text-muted hover:bg-page-hover hover:text-text\",\n )}\n >\n {item.icon && (\n <span\n className={cn(\n \"flex w-5 shrink-0 items-center justify-center\",\n isSelected ? \"text-text-muted\" : \"text-text-subtle\",\n )}\n >\n {item.icon}\n </span>\n )}\n <span className=\"min-w-0 flex-1 truncate\">{item.label}</span>\n {item.count !== undefined && item.count > 0 && (\n <span\n className={cn(\n \"shrink-0 text-xs tabular-nums\",\n isSelected\n ? \"rounded-full bg-accent px-1.5 font-semibold text-accent-fg\"\n : \"text-text-subtle\",\n action && swapsWithCount && \"group-hover/item:hidden group-focus-within/item:hidden\",\n )}\n >\n {item.count}\n </span>\n )}\n {action && (\n <button\n type=\"button\"\n aria-label={action.label}\n title={action.label}\n onClick={(e) => {\n e.stopPropagation();\n action.onClick();\n }}\n // Enter/Space bubbelt anders door naar de rij en navigeert alsnog.\n onKeyDown={(e) => e.stopPropagation()}\n className={cn(\n \"flex size-5 shrink-0 items-center justify-center rounded-sm\",\n \"text-text-subtle transition-colors duration-fast ease-out\",\n \"hover:bg-page-hover hover:text-text\",\n \"focus-visible:outline-none focus-visible:focus-ring\",\n swapsWithCount &&\n \"opacity-0 group-hover/item:opacity-100 focus-visible:opacity-100\",\n )}\n >\n {action.icon}\n </button>\n )}\n </div>\n </li>\n );\n};\n\n/**\n * Sidebar — een vrij slot (zoek) en daaronder de nav-items. Secties met\n * children zijn koppen, geen knoppen.\n *\n * Géén titel en géén actie-iconen meer: de app-switcher (titel + `+`) en de\n * gebruikersvoet zijn shell-chrome en staan in `NavigationPanel`. Dit component\n * vult alleen het middenstuk van die kolom.\n */\nexport const SidebarMenu: React.FC<SidebarMenuProps> = ({\n items,\n isSelectedHandler,\n onClick,\n preMenuItemsComponent,\n loading = false,\n}) => {\n if (loading) {\n return (\n <nav className=\"flex h-full min-h-0 shrink-0 flex-col\">\n {preMenuItemsComponent && <div className=\"pb-4\">{preMenuItemsComponent}</div>}\n <SidebarMenuSkeleton />\n </nav>\n );\n }\n\n return (\n <nav className=\"flex h-full min-h-0 shrink-0 flex-col\">\n {preMenuItemsComponent && <div className=\"pb-4\">{preMenuItemsComponent}</div>}\n\n <ul className=\"flex min-h-0 flex-1 flex-col gap-px overflow-y-auto\">\n {items.map((item, index) =>\n !item.path && !item.label && !item.children ? (\n <li key={index} aria-hidden className=\"h-4\" />\n ) : (\n <SidebarMenuItem\n key={index}\n item={item}\n isSelectedHandler={isSelectedHandler}\n onClick={onClick}\n />\n )\n )}\n </ul>\n </nav>\n );\n};\n\nexport default SidebarMenu;\n","import React from 'react';\nimport { cn } from '../utils/cn';\n\nexport interface HeadingProps {\n /** Heading level */\n level?: 1 | 2 | 3 | 4 | 5 | 6;\n /** Visual size (can be different from semantic level) */\n size?: 'xs' | 'sm' | 'md' | 'lg' | 'xl' | '2xl' | '3xl' | '4xl';\n /** Font weight */\n weight?: 'light' | 'normal' | 'medium' | 'semibold' | 'bold';\n /** Text color */\n color?: 'primary' | 'secondary' | 'accent' | 'success' | 'warning' | 'error' | 'info' | 'neutral' | 'current';\n /** Text alignment */\n align?: 'left' | 'center' | 'right';\n /** Whether to truncate text with ellipsis */\n truncate?: boolean;\n /** Additional CSS classes */\n className?: string;\n /** Child content */\n children: React.ReactNode;\n}\n\n/**\n * Heading — semantic level, visual size from the token scale.\n *\n * md 13 · lg 16 (section head) · xl 20 (detail title)\n * 2xl 24 (page title) · 3xl / 4xl 30 (display)\n *\n * Default weight is semibold: the system has no 700 headings.\n */\nconst sizeMap: Record<NonNullable<HeadingProps['size']>, string> = {\n xs: 'text-xs',\n sm: 'text-sm',\n md: 'text-base',\n lg: 'text-lg',\n xl: 'text-xl',\n '2xl': 'text-2xl',\n '3xl': 'text-3xl',\n '4xl': 'text-3xl',\n};\n\nconst weightMap: Record<NonNullable<HeadingProps['weight']>, string> = {\n light: 'font-normal',\n normal: 'font-normal',\n medium: 'font-medium',\n semibold: 'font-semibold',\n bold: 'font-bold',\n};\n\nconst colorMap: Record<NonNullable<HeadingProps['color']>, string> = {\n primary: 'text-text',\n secondary: 'text-text-muted',\n accent: 'text-accent',\n success: 'text-success-fg',\n warning: 'text-warning-fg',\n error: 'text-danger-fg',\n info: 'text-info-fg',\n neutral: 'text-text',\n current: 'text-current',\n};\n\nconst alignMap: Record<NonNullable<HeadingProps['align']>, string> = {\n left: 'text-left',\n center: 'text-center',\n right: 'text-right',\n};\n\nexport const Heading: React.FC<HeadingProps> = ({\n level = 1,\n size,\n weight = 'semibold',\n color = 'current',\n align = 'left',\n truncate = false,\n className,\n children,\n ...props\n}) => {\n const Tag = `h${level}` as keyof React.JSX.IntrinsicElements;\n\n const headingClasses = cn(\n 'font-sans text-pretty',\n sizeMap[size || getDefaultSize(level)!],\n weightMap[weight],\n colorMap[color],\n alignMap[align],\n truncate && 'truncate',\n className\n );\n\n return (\n <Tag className={headingClasses} {...props}>\n {children}\n </Tag>\n );\n};\n\nfunction getDefaultSize(level: number): HeadingProps['size'] {\n const sizeMap: Record<number, HeadingProps['size']> = {\n 1: '2xl',\n 2: 'xl',\n 3: 'lg',\n 4: 'lg',\n 5: 'md',\n 6: 'md',\n };\n\n return sizeMap[level] || 'md';\n}\n","import { ChevronRight, Search } from \"lucide-react\";\nimport React, { useEffect, useRef, useState } from \"react\";\n\n// Define the types for the command palette\nexport interface Command {\n id: string;\n label: string;\n action?: () => void;\n subCommands?: Command[];\n icon?: React.ReactNode;\n}\n\nexport interface CommandPaletteProps {\n commands: Command[];\n isOpen: boolean;\n onClose: () => void;\n labels?: {\n searchPlaceholder?: string;\n navigate?: string;\n select?: string;\n close?: string;\n noCommandsFound?: string;\n };\n initialCommandPath?: string[];\n initialActiveIndex?: number;\n}\n\nconst CommandPalette: React.FC<CommandPaletteProps> = ({\n commands,\n isOpen,\n onClose,\n labels,\n initialCommandPath,\n initialActiveIndex,\n}) => {\n const [searchTerm, setSearchTerm] = useState(\"\");\n const [activeCommandPath, setActiveCommandPath] = useState<string[]>(initialCommandPath || []);\n const [activeIndex, setActiveIndex] = useState(initialActiveIndex || 0);\n const paletteRef = useRef<HTMLDivElement>(null);\n const listRef = useRef<HTMLDivElement>(null);\n\n const currentCommands = activeCommandPath.length\n ? commands.find((c) => c.id === activeCommandPath[0])?.subCommands || []\n : commands;\n\n const filteredCommands = currentCommands.filter((command) =>\n command.label.toLowerCase().includes(searchTerm.toLowerCase())\n );\n\n // Reset state when the palette is closed\n useEffect(() => {\n if (!isOpen) {\n setSearchTerm(\"\");\n setActiveCommandPath(initialCommandPath || []);\n setActiveIndex(initialActiveIndex || 0);\n }\n }, [isOpen]);\n\n // Handle keyboard navigation\n useEffect(() => {\n const handleKeyDown = (event: KeyboardEvent) => {\n if (!isOpen) return;\n\n if (event.key === \"Escape\") {\n onClose();\n } else if (event.key === \"ArrowUp\") {\n setActiveIndex((prevIndex) =>\n prevIndex > 0 ? prevIndex - 1 : filteredCommands.length - 1\n );\n } else if (event.key === \"ArrowDown\") {\n setActiveIndex((prevIndex) =>\n prevIndex < filteredCommands.length - 1 ? prevIndex + 1 : 0\n );\n } else if (event.key === \"Enter\") {\n const command = filteredCommands[activeIndex];\n if (command) {\n if (command.subCommands) {\n setActiveCommandPath([...activeCommandPath, command.id]);\n setActiveIndex(0);\n } else if (command.action) {\n command.action();\n onClose();\n }\n }\n }\n };\n\n document.addEventListener(\"keydown\", handleKeyDown);\n return () => document.removeEventListener(\"keydown\", handleKeyDown);\n }, [isOpen, onClose, filteredCommands, activeIndex, activeCommandPath]);\n\n // Handle clicks outside the palette to close it\n useEffect(() => {\n const handleClickOutside = (event: MouseEvent) => {\n if (\n paletteRef.current &&\n !paletteRef.current.contains(event.target as Node)\n ) {\n onClose();\n }\n };\n\n if (isOpen) {\n document.addEventListener(\"mousedown\", handleClickOutside);\n }\n return () => document.removeEventListener(\"mousedown\", handleClickOutside);\n }, [isOpen, onClose]);\n\n // Keep active item visible while scrolling via keyboard\n useEffect(() => {\n if (!isOpen) return;\n const el = listRef.current?.querySelector<HTMLElement>(`[data-index=\"${activeIndex}\"]`);\n el?.scrollIntoView({ block: \"nearest\" });\n }, [activeIndex, isOpen]);\n\n if (!isOpen) {\n return null;\n }\n\n return (\n <div className=\"fixed inset-0 z-modal flex items-center justify-center bg-scrim\">\n <div\n className=\"flex flex-col w-full max-w-lg max-h-dialog p-2 mx-auto rounded-lg border border-border shadow-modal bg-surface\"\n ref={paletteRef}\n >\n <div className=\"flex items-center gap-2 px-3 flex-shrink-0\">\n <Search className=\"w-4 h-4 text-text-muted shrink-0\" />\n <input\n type=\"text\"\n autoFocus\n placeholder={labels?.searchPlaceholder || \"Search commands...\"}\n value={searchTerm}\n onChange={(e) => setSearchTerm(e.target.value)}\n className=\"w-full border-0 bg-transparent py-2 text-text focus:outline-none\"\n />\n </div>\n <div\n ref={listRef}\n className=\"mt-2 pt-2 text-sm border-t border-border max-h-dialog-list overflow-y-auto\"\n >\n {filteredCommands.length === 0 && (\n <div className=\"text-text-muted text-center text-sm\">\n {labels?.noCommandsFound || \"No commands found\"}\n </div>\n )}\n {filteredCommands.map((command, index) => (\n <div\n key={command.id}\n data-index={index}\n className={`flex items-center p-2 cursor-pointer rounded-md ${index === activeIndex ? \"bg-accent-soft text-accent\" : \"text-text\"\n }`}\n onClick={() => {\n if (command.subCommands) {\n setActiveCommandPath([...activeCommandPath, command.id]);\n setActiveIndex(0);\n } else if (command.action) {\n command.action();\n onClose();\n }\n }}\n onMouseEnter={() => setActiveIndex(index)}\n >\n {command.icon && <span className=\"mr-3\">{command.icon}</span>}\n <span className=\"flex-grow\">{command.label}</span>\n {command.subCommands && (\n <span className=\"text-text-muted\">\n <ChevronRight className=\"w-4 h-4\" />\n </span>\n )}\n </div>\n ))}\n </div>\n <div className=\"flex items-center gap-4 px-3 pt-2 mt-2 text-xs text-text-muted border-t border-border\">\n <span className=\"flex items-center gap-1.5\">\n <kbd className=\"inline-flex items-center justify-center min-w-5 px-1 py-0.5 rounded border border-border bg-surface-sunk text-xs font-medium not-italic\">↑↓</kbd>\n {labels?.navigate || \"to navigate\"}\n </span>\n <span className=\"flex items-center gap-1.5\">\n <kbd className=\"inline-flex items-center justify-center min-w-5 px-1 py-0.5 rounded border border-border bg-surface-sunk text-xs font-medium not-italic\">↵</kbd>\n {labels?.select || \"to select\"}\n </span>\n <span className=\"flex items-center gap-1.5\">\n <kbd className=\"inline-flex items-center justify-center min-w-5 px-1 py-0.5 rounded border border-border bg-surface-sunk text-xs font-medium not-italic\">Esc</kbd>\n {labels?.close || \"to close\"}\n </span>\n </div>\n </div>\n </div>\n );\n};\n\nexport default CommandPalette;\n","import React, { forwardRef } from 'react';\nimport { cn } from '../utils/cn';\n\nexport interface BoxProps extends React.HTMLAttributes<HTMLDivElement> {\n /**\n * Padding size\n */\n padding?: 'none' | 'xs' | 'sm' | 'md' | 'lg' | 'xl' | '2xl';\n\n /**\n * Margin size\n */\n margin?: 'none' | 'xs' | 'sm' | 'md' | 'lg' | 'xl' | '2xl';\n\n /**\n * Background color\n */\n background?: 'none' | 'primary' | 'secondary' | 'accent' | 'success' | 'warning' | 'error' | 'info' | 'neutral' | 'white' | 'module' | 'module-subtle' | 'backdrop' | 'editor' | 'input';\n\n /**\n * Border radius\n */\n radius?: 'none' | 'sm' | 'md' | 'lg' | 'xl' | 'full';\n\n /**\n * Shadow size\n */\n shadow?: 'none' | 'sm' | 'md' | 'lg' | 'xl' | '2xl';\n\n /**\n * Border width\n */\n border?: 'none' | 'sm' | 'md' | 'lg';\n\n /**\n * Border color\n */\n borderColor?: 'primary' | 'secondary' | 'accent' | 'success' | 'warning' | 'error' | 'info' | 'neutral' | 'white';\n}\n\n/** 4px spacing scale only. */\nconst paddingMap = {\n none: 'p-0',\n xs: 'p-1',\n sm: 'p-2',\n md: 'p-4',\n lg: 'p-6',\n xl: 'p-8',\n '2xl': 'p-12',\n};\n\nconst marginMap = {\n none: 'm-0',\n xs: 'm-1',\n sm: 'm-2',\n md: 'm-4',\n lg: 'm-6',\n xl: 'm-8',\n '2xl': 'm-12',\n};\n\n/** Semantic surfaces — the legacy `module` names stay as aliases. */\nconst backgroundMap = {\n none: '',\n primary: 'bg-accent text-accent-fg',\n secondary: 'bg-surface-hover',\n accent: 'bg-accent-soft',\n success: 'bg-success-soft',\n warning: 'bg-warning-soft',\n error: 'bg-danger-soft',\n info: 'bg-info-soft',\n neutral: 'bg-surface-hover',\n white: 'bg-surface',\n module: 'bg-surface',\n 'module-subtle': 'bg-surface-sunk',\n backdrop: 'bg-page',\n editor: 'bg-surface',\n input: 'bg-surface-input',\n};\n\nconst radiusMap = {\n none: 'rounded-none',\n sm: 'rounded-sm',\n md: 'rounded-md',\n lg: 'rounded-lg',\n xl: 'rounded-xl',\n full: 'rounded-full',\n};\n\n/**\n * Elevation: cards are defined by their border, not a shadow — `sm` is\n * intentionally flat. Shadows only mean \"this floats above the page\".\n */\nconst shadowMap = {\n none: 'shadow-none',\n sm: 'shadow-none',\n md: 'shadow-overlay',\n lg: 'shadow-overlay',\n xl: 'shadow-modal',\n '2xl': 'shadow-modal',\n};\n\nconst borderMap = {\n none: 'border-0',\n sm: 'border',\n md: 'border-2',\n lg: 'border-4',\n};\n\nconst borderColorMap = {\n primary: 'border-accent-border',\n secondary: 'border-border',\n accent: 'border-accent-border',\n success: 'border-success-border',\n warning: 'border-warning-border',\n error: 'border-danger-border',\n info: 'border-info-border',\n neutral: 'border-border-subtle',\n white: 'border-border-subtle',\n};\n\n/**\n * Box primitive component for layout and styling\n *\n * @example\n * ```tsx\n * <Box padding=\"md\" background=\"module\" radius=\"lg\" border=\"sm\" borderColor=\"neutral\">\n * Content\n * </Box>\n * ```\n */\nexport const Box = forwardRef<HTMLDivElement, BoxProps>(\n (\n {\n padding,\n margin,\n background,\n radius,\n shadow,\n border,\n borderColor,\n className,\n children,\n ...props\n },\n ref\n ) => {\n return (\n <div\n ref={ref}\n className={cn(\n padding && paddingMap[padding],\n margin && marginMap[margin],\n background && backgroundMap[background],\n radius && radiusMap[radius],\n shadow && shadowMap[shadow],\n border && borderMap[border],\n borderColor && borderColorMap[borderColor],\n className\n )}\n {...props}\n >\n {children}\n </div>\n );\n }\n);\n\nBox.displayName = 'Box';\n","import { Box, BoxProps } from \"./Box\";\n\nexport interface CardProps extends BoxProps {\n children: React.ReactNode;\n title?: string;\n}\n\n/**\n * Card — panel on a page background. Border, never a shadow (radius-lg = 12px).\n */\nexport const Card = ({ children, title, ...props }: CardProps) => {\n return (\n <Box\n background=\"module\"\n radius=\"lg\"\n shadow=\"none\"\n border=\"sm\"\n borderColor=\"neutral\"\n {...props}\n >\n {title && (\n <span className=\"mb-2 block text-sm font-semibold text-text\">{title}</span>\n )}\n {children}\n </Box>\n );\n};\n","import React, { useEffect, useRef, useState } from \"react\";\n\ninterface FederatedResourceProps {\n identifier: string;\n resourceLoader: () => Promise<any>;\n framework?: 'react' | 'svelte' | 'vanilla';\n /** Getoond zolang de remote laadt. */\n fallback?: React.ReactNode;\n /**\n * Getoond wanneer de remote niet te laden is — app uitgezet, bundel stuk, sleutel fout.\n *\n * Zonder dit rendert dit component bij een fout niets, en dan verdwijnt de plek waar\n * iets had moeten staan zonder spoor in de UI. Dat is precies het verschil tussen \"de\n * app is er niet\" en \"er is niks aan de hand\".\n */\n errorFallback?: React.ReactNode;\n componentProps?: Record<string, any>;\n className?: string;\n}\n\n/**\n * Remotes die al een keer opgehaald zijn, op identifier.\n *\n * Zonder dit gaf élke identifier-wissel een leeg scherm: het component liet de huidige\n * remote los, toonde de `fallback` en ging op een promise wachten — óók als de bundel al\n * in het geheugen zat en die promise op de volgende tick zou resolven. Op een pagina die\n * bij het navigeren van resource wisselt (een publiek helpcentrum, een app die van lijst\n * naar editor gaat) is dat een schermvullende flits per klik.\n *\n * Module Federation cachet de onderliggende import zelf al; dit haalt dus de render-ronde\n * weg, niet een netwerkronde. Een app die tijdens de sessie vervangen wordt houdt daarmee\n * zijn oude module — net als vandaag, want die MF-cache zit er toch al tussen.\n */\nconst loadedRemotes = new Map<string, any>();\n\nexport function FederatedResource({\n identifier,\n resourceLoader,\n framework = 'react',\n fallback,\n errorFallback,\n componentProps,\n className,\n}: FederatedResourceProps) {\n const containerRef = useRef<HTMLDivElement>(null);\n const [failedId, setFailedId] = useState<string | null>(null);\n const [, bump] = useState(0);\n\n const svelteInstanceRef = useRef<any>(null);\n\n /**\n * De loader in een ref, en het effect alleen op `identifier`.\n *\n * Vrijwel elke aanroeper geeft een inline arrow mee (`() => sdk.resources.get(...)`).\n * Die heeft elke render een nieuwe identiteit, dus met de loader in de deps-array laadde\n * dit component bij élke render opnieuw. Onopvallend bij één paneel; niet bij een\n * feedrij per gesprek. `identifier` is de echte identiteit van de resource.\n *\n * Dit raakt `componentProps` niet: die worden in de render gespreid\n * (`<ExternalComponent {...componentProps} />`), niet in dit effect. Wijzigen ze, dan\n * hertekent dit component en krijgt de remote ze meteen — het is juist de bedoeling dat\n * de *bundel* niet opnieuw wordt gehaald omdat er een prop veranderde.\n *\n * Voor svelte lopen prop-updates via `$set` in het effect onderaan. Een `vanilla`-remote\n * krijgt zijn props alleen bij mount; er is vandaag geen enkele app die iets anders dan\n * `react` declareert, dus dat blijft een open eind in plaats van een geraden API.\n */\n const loaderRef = useRef(resourceLoader);\n loaderRef.current = resourceLoader;\n\n useEffect(() => {\n if (loadedRemotes.has(identifier)) return;\n\n let isMounted = true;\n\n const load = async () => {\n try {\n const module = await loaderRef.current();\n if (!isMounted) return;\n loadedRemotes.set(identifier, module);\n bump((n) => n + 1);\n } catch (err) {\n console.error(`[FederatedResource] Load failed: ${identifier}`, err);\n if (isMounted) setFailedId(identifier);\n }\n };\n\n void load();\n return () => { isMounted = false; };\n }, [identifier]);\n\n /*\n * Alles wordt in de render afgeleid uit `identifier`, niet uit state.\n *\n * State die bij de vórige identifier hoort is hier gevaarlijk: een effect draait ná de\n * paint, dus bij een wissel is er één frame waarin de oude remote de props van de\n * nieuwe krijgt. Dat is precies het moment waarop een pagina op een prop crasht die er\n * voor haar niet hoort te zijn.\n */\n const module = loadedRemotes.get(identifier) ?? null;\n // `!module` eerst: wisselt de identifier weg van een mislukte remote en weer terug, dan\n // probeert het effect het opnieuw. Slaagt die poging, dan mag de oude foutmelding niet\n // naast het geladen component blijven staan.\n const failed = !module && failedId === identifier;\n const isLoading = !module && !failed;\n\n const ExternalComponent = module\n ? framework === 'react'\n ? (module.component || module.default || module)\n : module\n : null;\n\n useEffect(() => {\n if (!ExternalComponent || framework === 'react') return;\n\n const target = containerRef.current;\n if (!target) return;\n\n if (framework === 'svelte') {\n const Component = ExternalComponent.default || ExternalComponent;\n const instance = new Component({ target, props: componentProps || {} });\n svelteInstanceRef.current = instance;\n return () => instance.$destroy();\n }\n\n if (ExternalComponent.mount) {\n const cleanup = ExternalComponent.mount({ container: target, props: componentProps || {} });\n return () => {\n if (typeof cleanup === 'function') cleanup();\n else ExternalComponent.unmount?.(target);\n };\n }\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [ExternalComponent, framework]);\n\n useEffect(() => {\n if (framework === 'svelte' && svelteInstanceRef.current) {\n svelteInstanceRef.current.$set?.(componentProps);\n }\n }, [componentProps, framework]);\n\n return (\n <div ref={containerRef} className={className} style={{ display: 'contents' }}>\n {isLoading && fallback}\n {failed && errorFallback}\n\n {framework === 'react' && ExternalComponent && (\n <ExternalComponent {...componentProps} />\n )}\n </div>\n );\n}\n","import type { ErrorInfo, ReactNode } from \"react\";\nimport { Component } from \"react\";\n\ninterface Props {\n children: ReactNode;\n fallback?: ReactNode;\n name?: string;\n}\n\ninterface State {\n hasError: boolean;\n error: Error | null;\n}\n\nexport class ErrorBoundary extends Component<Props, State> {\n public state: State = {\n hasError: false,\n error: null,\n };\n\n public static getDerivedStateFromError(error: Error): State {\n return { hasError: true, error };\n }\n\n public componentDidCatch(error: Error, errorInfo: ErrorInfo) {\n console.error(`[ErrorBoundary] Error in ${this.props.name || 'Component'}:`, error, errorInfo);\n }\n\n public render() {\n if (this.state.hasError) {\n if (this.props.fallback) {\n return this.props.fallback;\n }\n\n return (\n <div className=\"p-4 m-4 border border-danger-border bg-danger-soft rounded-lg\">\n <h2 className=\"text-lg font-semibold text-danger-fg\">Something went wrong</h2>\n <p className=\"text-sm text-danger-fg mt-1\">\n {this.props.name ? `Error in ${this.props.name}` : 'The component failed to render.'}\n </p>\n <button\n className=\"mt-4 px-4 py-2 bg-danger text-danger-fg rounded hover:opacity-90 transition-opacity text-sm\"\n onClick={() => this.setState({ hasError: false, error: null })}\n >\n Try again\n </button>\n </div>\n );\n }\n\n return this.props.children;\n }\n}\n"],"names":["cn","inputs","clsx","createVariants","variants","variant","value","createSizes","sizes","size","useAnchoredPosition","open","anchorRef","gap","matchWidth","placement","style","setStyle","useState","useLayoutEffect","place","anchor","rect","spaceBelow","spaceAbove","wantsTop","flip","onTop","next","IDENTITY_TONE_COUNT","hash","seed","h","i","identityTone","key","PLATE","SOLID","identityPlateClass","identityDotClass","TONES","catTone","id","text","normalizeText","MeetingGrid","tiles","pinned","className","jsx","t","cols","ParticipantTile","name","avatarUrl","muted","speaking","hasVideo","videoSlot","fill","jsxs","VideoOff","User","MicOff","Mic","VideoSurface","attach","active","mirrored","ref","useRef","useEffect","cleanup","buttonVariants","buttonSizes","iconOnlySizes","Button","forwardRef","fullWidth","loading","leftIcon","rightIcon","iconOnly","shape","children","disabled","props","isDisabled","ButtonGroup","orientation","attached","baseClasses","resolveLucideIcon","pascal","part","found","LucideIcons","colorMap","Icon","IconComponent","color","clickable","onClick","ariaLabel","sizeValue","getSizeValue","iconClasses","iconProps","e","Popover","trigger","rootClassName","triggerClassName","triggerLabel","isOpen","setIsOpen","rootRef","triggerRef","panelStyle","onDown","event","onEsc","handleToggle","close","tones","chipShell","opts","chipBody","FilterChip","label","icon","tone","caret","menu","menuClassName","onClear","clearLabel","title","showClear","radius","shell","body","Fragment","ChevronDown","bodyClasses","clearButton","X","sizeMap","buttonBackgroundMap","Link","external","href","target","rel","isExternal","linkProps","ExternalLink","SegmentedToggle","options","onChange","opt","variantStyles","chevronSizes","SplitButton","menuPlacement","menuLabel","hasMenu","option","checkboxSizes","rowSizes","labelSizes","Checkbox","helperText","error","indeterminate","containerClassName","labelClassName","reactId","React","checkboxId","hasError","innerRef","setRefs","node","weightMap","alignMap","lineHeightMap","Text","weight","align","truncate","italic","underline","lineHeight","as","Tag","getDefaultElement","isCaption","isLabel","isCode","textClasses","ImageField","maxDimension","maxBytes","aspect","chooseLabel","removeLabel","tooLargeLabel","inputRef","setError","handleSelect","file","encoded","downscaleToDataUri","approximateBytes","dataUri","base64","padding","resolve","reject","reader","img","scale","width","height","canvas","ctx","CalendarIcon","Calendar","ChevronLeftIcon","ChevronLeft","ChevronRightIcon","ChevronRight","DatePicker","placeholder","required","minDate","maxDate","format","withTime","currentMonth","setCurrentMonth","containerRef","fieldRef","handleClickOutside","formatDate","date","day","month","year","datePart","formatTime","handleTimeChange","hours","minutes","base","getCalendarDays","firstDay","startDate","days","current","handleDateSelect","picked","handlePrevMonth","handleNextMonth","handleClear","inputClasses","calendarDays","monthNames","index","isCurrentMonth","isSelected","isToday","selectSizes","norm","Select","searchable","multiple","allowCreate","onCreateOption","selectId","searchTerm","setSearchTerm","localOptions","setLocalOptions","includesOption","needle","o","ensureValuesInOptions","baseOptions","currentValue","out","addIfMissing","v","val","prev","selected","optionValue","currentValues","newValues","selectedOption","selectedOptions","filteredOptions","canCreate","createOption","labelToCreate","clean","newOption","getDisplayValue","ChevronDownIcon","inputSizes","fieldLabelClasses","fieldFrameClasses","fieldEdgeClasses","TextField","startIcon","endIcon","inputId","describedBy","FolderSelect","onListFolders","templatePlaceholder","showTemplate","folders","setFolders","res","f","classes","SearchIcon","Search","iconSizes","SearchableTextField","externalLoading","onRemoteSearch","onSelect","debounceTime","showAllOnOpen","propValue","inputValue","setInputValue","isSearchingRemote","setIsSearchingRemote","typedSinceOpen","setTypedSinceOpen","useMemo","lowerCaseInput","handler","handleChange","newValue","handleFocus","showDropdown","resolvedRef","Loader2","SearchField","onValueChange","hint","Switch","checked","track","Dropdown","showCheck","header","hoveredOption","setHoveredOption","submenuPosition","setSubmenuPosition","dropdownRef","submenuRef","menuRef","menuPos","hideTimeoutRef","menuItems","handleMenuKeyDown","items","handleEscape","hoveredElement","handleTriggerClick","handleOptionClick","parentValue","handleOptionHover","handleOptionLeave","handleSubmenuOptionClick","dropdownClasses","submenuClasses","hasChildren","isHovered","Check","childOption","childIndex","totalOptions","count","childCount","child","PageToolbarActions","actions","defaultVariant","action","paddingClasses","PageToolbar","onBack","backLabel","dateFilterHandler","fn","selectFilterHandler","cellPadding","rowHeights","SKELETON_ROWS","SKELETON_WIDTHS","pageWindow","total","_","sorted","p","a","b","page","FilterMenu","values","labelOf","pick","Table","data","columns","searchPlaceholder","searchValue","onSearchChange","filters","toolbarActions","paginated","defaultPageSize","onRowClick","selectable","selectedRows","onSelectionChange","getRowKey","row","emptyContent","footerSummary","hoverable","rowClassName","headerBackground","internalSearch","setInternalSearch","controlledSearch","sortState","setSortState","pagination","setPagination","tableRef","filteredData","result","searchableColumns","col","lowerSearchTerm","column","filter","sortedData","aValue","bValue","comparison","paginatedData","startIndex","endIndex","handleSort","useCallback","columnId","handlePageChange","newPage","handleRowSelection","rowKey","handleSelectAll","totalItems","totalPages","startItem","endItem","allVisibleSelected","selectedRow","someVisibleSelected","pad","headerFill","cellClasses","showToolbar","showPaginator","showFooter","ChevronUp","rowIndex","columnIndex","Ellipsis","actionId","entry","TabsContext","createContext","TabBar","activeTab","onTabChange","internalActiveTab","setInternalActiveTab","currentActiveTab","handleTabClick","tabId","item","Tabs","defaultTab","handleTabChange","contextValue","activeTabItem","tabListClasses","tabClasses","isActive","sizeClasses","variantClasses","stateClasses","activeClasses","inactiveClasses","modalSizes","Modal","onClose","closeOnBackdropClick","closeOnEscape","backdropClassName","footer","showCloseButton","modalRef","previousActiveElement","handleBackdropClick","StorageInput","accept","onListFiles","onListMounts","onUploadFile","onDownloadFile","onRegisterFile","isModalOpen","setIsModalOpen","mounts","setMounts","selectedMount","setSelectedMount","currentPath","setCurrentPath","remoteFiles","setRemoteFiles","setLoading","selectedPointer","setSelectedPointer","isCreatingFolder","setIsCreatingFolder","newFolderName","setNewFolderName","fileInputRef","loadMounts","loadFiles","resp","err","handleLocalOnlySelection","buffer","content","virtualPointer","handleUploadToStorage","pointer","handleCreateFolder","fullPath","handleSelectRemote","explorerItems","files","path","parts","handleFolderClick","folderName","handleGoBack","tableData","explorerColumns","Folder","FileText","mountColumns","HardDrive","ArrowLeft","FolderPlus","Upload","textareaSizes","TextArea","rows","textareaId","REAL_TOKENS","autofillProps","token","getValueByPath","obj","acc","setValueByPath","keys","clone","cur","k","unsetByPath","FormSection","description","Form","groups","externalData","onSubmit","onCancel","transform","validate","submitButton","cancelButton","showButtons","layout","sdk","formData","setFormData","errors","setErrors","touched","setTouched","validateField","currentData","field","group","arrayErrors","hasErrors","rowErrors","subField","subFieldValue","handleFieldChange","newData","g","handleSubmit","newErrors","allFields","formErrors","finalData","renderField","commonProps","payload","fileId","arrayValue","handleAddItem","handleRemoveItem","handleSubFieldChange","fieldName","fieldValue","newArray","subFieldError","commonSubFieldProps","dateValue","Trash2","Plus","renderGroup","visibleItems","groupClasses","fieldError","formClasses","buttonSize","ConfirmDialog","confirmLabel","cancelLabel","onConfirm","badgeVariants","badgeSizes","dotColors","Badge","dot","dismissible","onDismiss","Bar","Shape","r","c","DEFAULT_ROWS","ContentLoading","showTableSkeleton","tableColumns","tableRows","resolvedShape","resolvedRows","resolvedColumns","inner","toneDisc","EmptyState","card","Kbd","trackSizes","fillVariants","ProgressBar","pct","spinnerSizes","spinnerColors","Spinner","showLabel","StatusDot","pulse","StepIndicator","steps","activeIndex","shared","step","HTML_TAG","HTML_PROSE","components","RichText","src","DOMPurify","Markdown","remarkGfm","KPI_TONE","CALLOUT_TONE","KPI_COLUMNS","Block","block","List","cellIndex","ArtifactView","blocks","runtime","AssistantCard","Sparkles","toneClasses","initials","Avatar","errored","setErrored","RING","OWNER_RING","AvatarStack","people","max","shown","overflow","CH","ChannelBadge","channel","known","Image","alt","aspectRatio","showLoading","showError","fallback","loadingContent","errorContent","onLoad","onError","isLoading","setIsLoading","setHasError","currentSrc","setCurrentSrc","handleLoad","handleError","containerClasses","imageClasses","placeholderClasses","defaultLoadingContent","defaultErrorContent","ImageOff","ListBulkAction","leading","renderItem","trailing","onActiveIndexChange","unread","dimmed","groupBy","renderGroupHeader","stickyGroupHeaders","collapsibleGroups","hideGroupCount","selectedItems","bulkActions","stickyHeader","bordered","loadingRows","collapsed","setCollapsed","handleKeyDown","keyOf","toggle","toggleAll","container","allSelected","someSelected","renderRow","firstInBlock","isUnread","isDimmed","buckets","declared","groupIndex","isCollapsed","MessageBubble","side","continued","valueTone","KpiCard","PageHeader","surface","subtitle","meta","backClassName","editable","onTitleChange","isEditing","setIsEditing","editValue","setEditValue","handleTitleClick","handleBlur","Pencil","Page","headerContent","loadingShape","empty","scroll","contentClassName","SectionCaption","SectionDivider","rule","SettingsFrameContext","SettingsFrameProvider","useSettingsFrame","useContext","useSettingsFrameHost","state","setState","api","ownerId","SettingsPage","secondaryActions","frame","useId","backRef","hasBack","SettingsRow","control","SettingsSection","SourceChip","dotColor","ArrowUpRight","badgeColumn","config","accessor","visible","sortable","_value","raw","booleanBadgeColumn","onLabel","offLabel","onTone","offTone","on","labelsColumn","separator","labelled","code","View","formatCheckbox","getOptionLabel","subValue","displayValue","formatted","viewClasses","SidebarMenuSkeleton","SidebarMenuItem","isSelectedHandler","depth","swapsWithCount","SidebarMenu","preMenuItemsComponent","Heading","level","headingClasses","getDefaultSize","CommandPalette","commands","labels","initialCommandPath","initialActiveIndex","activeCommandPath","setActiveCommandPath","setActiveIndex","paletteRef","listRef","filteredCommands","command","prevIndex","paddingMap","marginMap","backgroundMap","radiusMap","shadowMap","borderMap","borderColorMap","Box","margin","background","shadow","border","borderColor","Card","loadedRemotes","FederatedResource","identifier","resourceLoader","framework","errorFallback","componentProps","failedId","setFailedId","bump","svelteInstanceRef","loaderRef","isMounted","module","n","failed","ExternalComponent","Component","instance","ErrorBoundary","errorInfo"],"mappings":"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"}
|