@veltrixsecops/app-sdk 3.1.0 → 3.2.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/{chunk-6KUTYJW5.js → chunk-EOOEHZGC.js} +1 -1
- package/dist/{chunk-6KUTYJW5.js.map → chunk-EOOEHZGC.js.map} +1 -1
- package/dist/client/index.cjs.map +1 -1
- package/dist/client/index.d.cts +12 -3
- package/dist/client/index.d.ts +12 -3
- package/dist/client/index.js +1 -1
- package/dist/hooks/index.cjs +7 -0
- package/dist/hooks/index.cjs.map +1 -1
- package/dist/hooks/index.d.cts +24 -3
- package/dist/hooks/index.d.ts +24 -3
- package/dist/hooks/index.js +7 -1
- package/dist/hooks/index.js.map +1 -1
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/ui/index.cjs +112 -0
- package/dist/ui/index.cjs.map +1 -1
- package/dist/ui/index.d.cts +130 -1
- package/dist/ui/index.d.ts +130 -1
- package/dist/ui/index.js +109 -1
- package/dist/ui/index.js.map +1 -1
- package/dist/{use-app-context-SEU1tyZd.d.cts → use-app-context-OQlcmq7t.d.cts} +36 -1
- package/dist/{use-app-context-SEU1tyZd.d.ts → use-app-context-OQlcmq7t.d.ts} +36 -1
- package/package.json +1 -1
package/dist/ui/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/ui/index.tsx"],"sourcesContent":["// ========================================================================\n// @veltrixsecops/app-sdk/ui — the platform's shared component library,\n// exposed to app client bundles.\n//\n// App pages import these instead of hand-rolling raw HTML, so pages render\n// themed inside the Veltrix design system (dark/light + tenant branding via\n// `var(--vx-*)`), consistent with the rest of the portal, and externalized —\n// zero bundle bloat, one React instance. This completes the \"predictable\n// shell, flexible body\" contract: the platform owns the components; apps\n// compose their page body from them.\n//\n// RUNTIME: every export here reads its real implementation off the host at\n// render time — globalThis.__VELTRIX_APP_RUNTIME__.ui.<Name>, populated by\n// the platform from components/shared/* (see\n// client/src/appRuntime/installHostRuntime.ts). At packaging time the CLI's\n// client bundler (and the platform's on-demand esbuild bundle routes) shim\n// the '@veltrixsecops/app-sdk/ui' specifier straight to that `ui` bag, so\n// this module's own render-time lookup only actually executes in\n// non-bundled contexts: local dev, unit tests, a bare `tsc --noEmit`, or\n// Storybook.\n//\n// FALLBACK CONTRACT: outside the platform (host runtime absent, or an older\n// host that predates a given component) every export here renders a\n// minimal, accessible, unstyled fallback instead of throwing — an app page\n// under test or local dev keeps working, just without platform theming.\n// Never throw on render.\n//\n// TYPE FIDELITY: prop types are copied from the platform's real components\n// in client/src/components/shared (see the ADR at\n// _ai_tasks/ui-package/2026-07-10/02_sdk_ui_subpath.md) so app-author\n// typechecking matches what actually renders inside Veltrix. Heavy composite\n// widgets (ConfigurationCanvas, VersionControl, Pipeline) stay out of scope —\n// they carry platform coupling a later phase may expose read-only versions\n// of; see the ADR's \"Non-goals\" section.\n//\n// useToast / useConfirmDialog are included because the platform's root\n// App.tsx mounts ToastProvider/ConfirmationDialogProvider around the ENTIRE\n// tree (including every app page, since app pages render inside the host's\n// own React instance) — so the real context-backed hooks resolve correctly\n// from app code with no extra wiring. Outside the platform they degrade to a\n// safe, non-throwing fallback (see each hook's docs below) rather than\n// crashing or silently doing nothing.\n// ========================================================================\n\nimport * as React from 'react'\nimport { getHostRuntime } from '../client'\n\n/** Read one named component off the host's `runtime.ui` bag, or undefined. */\nfunction getHostUi<T>(name: string): T | undefined {\n return getHostRuntime()?.ui?.[name] as T | undefined\n}\n\nconst fallbackNote: React.CSSProperties = { fontFamily: 'inherit' }\n\n// ---------------------------------------------------------------------------\n// Button\n// ---------------------------------------------------------------------------\n\nexport type ButtonVariant = 'primary' | 'secondary' | 'danger' | 'success' | 'warning' | 'ghost' | 'link'\nexport type ButtonSize = 'sm' | 'md' | 'lg'\n\nexport interface ButtonProps extends React.ButtonHTMLAttributes<HTMLButtonElement> {\n variant?: ButtonVariant\n size?: ButtonSize\n isLoading?: boolean\n loadingText?: string\n fullWidth?: boolean\n leftIcon?: React.ReactNode\n rightIcon?: React.ReactNode\n}\n\ntype ButtonComponent = React.ForwardRefExoticComponent<ButtonProps & React.RefAttributes<HTMLButtonElement>>\n\n/**\n * Button — delegates to the platform's real Button at render time.\n *\n * @example\n * <Button variant=\"primary\" leftIcon={<RefreshIcon />} onClick={refresh}>Refresh</Button>\n */\nexport const Button = React.forwardRef<HTMLButtonElement, ButtonProps>((props, ref) => {\n const HostButton = getHostUi<ButtonComponent>('Button')\n if (HostButton) return <HostButton ref={ref} {...props} />\n\n const {\n variant: _variant,\n size: _size,\n isLoading,\n loadingText,\n fullWidth,\n leftIcon,\n rightIcon,\n children,\n disabled,\n type,\n style,\n ...rest\n } = props\n\n return (\n <button\n ref={ref}\n type={type ?? 'button'}\n disabled={disabled || isLoading}\n aria-busy={isLoading || undefined}\n style={{\n ...fallbackNote,\n display: 'inline-flex',\n alignItems: 'center',\n gap: 6,\n padding: '6px 14px',\n borderRadius: 6,\n border: '1px solid currentColor',\n background: 'transparent',\n cursor: disabled || isLoading ? 'not-allowed' : 'pointer',\n width: fullWidth ? '100%' : undefined,\n opacity: disabled || isLoading ? 0.6 : 1,\n justifyContent: 'center',\n ...style,\n }}\n {...rest}\n >\n {leftIcon}\n {isLoading ? loadingText ?? children : children}\n {rightIcon}\n </button>\n )\n})\nButton.displayName = 'Button'\n\n// ---------------------------------------------------------------------------\n// Badge\n// ---------------------------------------------------------------------------\n\nexport type BadgeVariant = 'default' | 'primary' | 'secondary' | 'success' | 'danger' | 'warning' | 'info'\nexport type BadgeSize = 'sm' | 'md' | 'lg'\n\nexport interface BadgeProps extends React.HTMLAttributes<HTMLSpanElement> {\n variant?: BadgeVariant\n size?: BadgeSize\n rounded?: boolean\n dot?: boolean\n}\n\nconst BADGE_FALLBACK_COLORS: Record<BadgeVariant, string> = {\n default: '#6b7280',\n primary: '#4f46e5',\n secondary: '#6b7280',\n success: '#16a34a',\n danger: '#dc2626',\n warning: '#d97706',\n info: '#0284c7',\n}\n\n/**\n * Badge — delegates to the platform's real Badge at render time.\n *\n * @example\n * <Badge variant={row.deployState === 'deployed' ? 'success' : 'warning'}>{row.deployState}</Badge>\n */\nexport const Badge: React.FC<BadgeProps> = ({ variant = 'default', size = 'md', rounded, dot, children, style, ...rest }) => {\n const HostBadge = getHostUi<React.FC<BadgeProps>>('Badge')\n if (HostBadge) return <HostBadge variant={variant} size={size} rounded={rounded} dot={dot} style={style} {...rest}>{children}</HostBadge>\n\n const color = BADGE_FALLBACK_COLORS[variant]\n const fontSize = size === 'sm' ? 11 : size === 'lg' ? 14 : 12\n return (\n <span\n style={{\n ...fallbackNote,\n display: 'inline-flex',\n alignItems: 'center',\n gap: 4,\n padding: size === 'sm' ? '1px 6px' : size === 'lg' ? '3px 10px' : '2px 8px',\n borderRadius: rounded ? 999 : 4,\n border: `1px solid ${color}`,\n color,\n fontSize,\n fontWeight: 500,\n ...style,\n }}\n {...rest}\n >\n {dot && <span aria-hidden=\"true\" style={{ width: 6, height: 6, borderRadius: '50%', background: color }} />}\n {children}\n </span>\n )\n}\nBadge.displayName = 'Badge'\n\n// ---------------------------------------------------------------------------\n// Card (+ Header/Body/Footer)\n// ---------------------------------------------------------------------------\n\nexport interface CardProps extends React.HTMLAttributes<HTMLDivElement> {\n variant?: 'default' | 'bordered' | 'elevated'\n padding?: 'none' | 'sm' | 'md' | 'lg'\n}\nexport interface CardHeaderProps extends React.HTMLAttributes<HTMLDivElement> {\n actions?: React.ReactNode\n}\nexport type CardBodyProps = React.HTMLAttributes<HTMLDivElement>\nexport interface CardFooterProps extends React.HTMLAttributes<HTMLDivElement> {\n variant?: 'default' | 'bordered'\n}\n\n/** Card — delegates to the platform's real Card at render time. */\nexport const Card: React.FC<CardProps> = ({ children, style, ...rest }) => {\n const HostCard = getHostUi<React.FC<CardProps>>('Card')\n if (HostCard) return <HostCard style={style} {...rest}>{children}</HostCard>\n return (\n <div style={{ ...fallbackNote, border: '1px solid #d1d5db', borderRadius: 8, overflow: 'hidden', ...style }} {...rest}>\n {children}\n </div>\n )\n}\nCard.displayName = 'Card'\n\n/** CardHeader — the header section of a Card, with optional trailing actions. */\nexport const CardHeader: React.FC<CardHeaderProps> = ({ actions, children, style, ...rest }) => {\n const HostCardHeader = getHostUi<React.FC<CardHeaderProps>>('CardHeader')\n if (HostCardHeader) return <HostCardHeader actions={actions} style={style} {...rest}>{children}</HostCardHeader>\n return (\n <div\n style={{\n ...fallbackNote,\n padding: '12px 16px',\n borderBottom: '1px solid #d1d5db',\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'space-between',\n gap: 12,\n ...style,\n }}\n {...rest}\n >\n <div style={{ flex: 1, minWidth: 0 }}>{children}</div>\n {actions && <div>{actions}</div>}\n </div>\n )\n}\nCardHeader.displayName = 'CardHeader'\n\n/** CardBody — the main content area of a Card. */\nexport const CardBody: React.FC<CardBodyProps> = ({ children, style, ...rest }) => {\n const HostCardBody = getHostUi<React.FC<CardBodyProps>>('CardBody')\n if (HostCardBody) return <HostCardBody style={style} {...rest}>{children}</HostCardBody>\n return (\n <div style={{ ...fallbackNote, padding: '12px 16px', ...style }} {...rest}>\n {children}\n </div>\n )\n}\nCardBody.displayName = 'CardBody'\n\n/** CardFooter — the footer section of a Card, typically for actions. */\nexport const CardFooter: React.FC<CardFooterProps> = ({ children, style, ...rest }) => {\n const HostCardFooter = getHostUi<React.FC<CardFooterProps>>('CardFooter')\n if (HostCardFooter) return <HostCardFooter style={style} {...rest}>{children}</HostCardFooter>\n return (\n <div style={{ ...fallbackNote, padding: '12px 16px', borderTop: '1px solid #d1d5db', ...style }} {...rest}>\n {children}\n </div>\n )\n}\nCardFooter.displayName = 'CardFooter'\n\n// ---------------------------------------------------------------------------\n// Input\n// ---------------------------------------------------------------------------\n\nexport type InputSize = 'sm' | 'md' | 'lg'\nexport type InputVariant = 'default' | 'error' | 'success'\n\nexport interface InputProps extends Omit<React.InputHTMLAttributes<HTMLInputElement>, 'size'> {\n label?: string\n error?: string\n helperText?: string\n leftIcon?: React.ReactNode\n rightIcon?: React.ReactNode\n variant?: InputVariant\n inputSize?: InputSize\n isSuccess?: boolean\n fullWidth?: boolean\n}\n\ntype InputComponent = React.ForwardRefExoticComponent<InputProps & React.RefAttributes<HTMLInputElement>>\n\n/**\n * Input — delegates to the platform's real Input at render time.\n *\n * @example\n * <Input label=\"Index name\" value={name} onChange={(e) => setName(e.target.value)} error={errors.name} />\n */\nexport const Input = React.forwardRef<HTMLInputElement, InputProps>((props, ref) => {\n const HostInput = getHostUi<InputComponent>('Input')\n if (HostInput) return <HostInput ref={ref} {...props} />\n\n const { label, error, helperText, leftIcon, rightIcon, fullWidth = true, id, style, ...rest } = props\n const inputId = id ?? (label ? `vx-input-${label.toLowerCase().replace(/\\s+/g, '-')}` : undefined)\n\n return (\n <div style={{ ...fallbackNote, width: fullWidth ? '100%' : undefined }}>\n {label && (\n <label htmlFor={inputId} style={{ display: 'block', fontSize: 13, fontWeight: 500, marginBottom: 4 }}>\n {label}\n </label>\n )}\n <div style={{ display: 'flex', alignItems: 'center', gap: 6 }}>\n {leftIcon}\n <input\n ref={ref}\n id={inputId}\n aria-invalid={!!error || undefined}\n style={{ flex: 1, padding: '6px 10px', borderRadius: 6, border: '1px solid #9ca3af', ...style }}\n {...rest}\n />\n {rightIcon}\n </div>\n {error && (\n <p role=\"alert\" style={{ marginTop: 4, fontSize: 12, color: '#dc2626' }}>\n {error}\n </p>\n )}\n {helperText && !error && <p style={{ marginTop: 4, fontSize: 12, color: '#6b7280' }}>{helperText}</p>}\n </div>\n )\n})\nInput.displayName = 'Input'\n\n// ---------------------------------------------------------------------------\n// Textarea\n// ---------------------------------------------------------------------------\n\nexport interface TextareaProps extends React.TextareaHTMLAttributes<HTMLTextAreaElement> {\n label?: string\n error?: string\n helperText?: string\n fullWidth?: boolean\n}\n\ntype TextareaComponent = React.ForwardRefExoticComponent<TextareaProps & React.RefAttributes<HTMLTextAreaElement>>\n\n/**\n * Textarea — delegates to the platform's real Textarea at render time.\n *\n * @example\n * <Textarea label=\"Description\" helperText=\"Markdown is supported.\" />\n */\nexport const Textarea = React.forwardRef<HTMLTextAreaElement, TextareaProps>((props, ref) => {\n const HostTextarea = getHostUi<TextareaComponent>('Textarea')\n if (HostTextarea) return <HostTextarea ref={ref} {...props} />\n\n const { label, error, helperText, fullWidth = true, id, rows = 4, style, ...rest } = props\n const textareaId = id ?? (label ? `vx-textarea-${label.toLowerCase().replace(/\\s+/g, '-')}` : undefined)\n\n return (\n <div style={{ ...fallbackNote, width: fullWidth ? '100%' : undefined }}>\n {label && (\n <label htmlFor={textareaId} style={{ display: 'block', fontSize: 13, fontWeight: 500, marginBottom: 4 }}>\n {label}\n </label>\n )}\n <textarea\n ref={ref}\n id={textareaId}\n rows={rows}\n aria-invalid={!!error || undefined}\n style={{ width: '100%', padding: '6px 10px', borderRadius: 6, border: '1px solid #9ca3af', ...style }}\n {...rest}\n />\n {error && (\n <p role=\"alert\" style={{ marginTop: 4, fontSize: 12, color: '#dc2626' }}>\n {error}\n </p>\n )}\n {helperText && !error && <p style={{ marginTop: 4, fontSize: 12, color: '#6b7280' }}>{helperText}</p>}\n </div>\n )\n})\nTextarea.displayName = 'Textarea'\n\n// ---------------------------------------------------------------------------\n// Checkbox\n// ---------------------------------------------------------------------------\n\nexport interface CheckboxProps extends Omit<React.InputHTMLAttributes<HTMLInputElement>, 'type'> {\n label?: React.ReactNode\n error?: string\n helperText?: string\n}\n\ntype CheckboxComponent = React.ForwardRefExoticComponent<CheckboxProps & React.RefAttributes<HTMLInputElement>>\n\n/**\n * Checkbox — delegates to the platform's real Checkbox at render time.\n *\n * @example\n * <Checkbox label=\"Enable drift detection\" checked={enabled} onChange={(e) => setEnabled(e.target.checked)} />\n */\nexport const Checkbox = React.forwardRef<HTMLInputElement, CheckboxProps>((props, ref) => {\n const HostCheckbox = getHostUi<CheckboxComponent>('Checkbox')\n if (HostCheckbox) return <HostCheckbox ref={ref} {...props} />\n\n const { label, error, helperText, id, disabled, ...rest } = props\n const generatedId = React.useId()\n const inputId = id ?? generatedId\n\n return (\n <div style={fallbackNote}>\n <div style={{ display: 'flex', alignItems: 'center', gap: 8 }}>\n <input ref={ref} id={inputId} type=\"checkbox\" disabled={disabled} aria-invalid={!!error || undefined} {...rest} />\n {label && (\n <label htmlFor={inputId} style={{ fontSize: 13, cursor: disabled ? 'not-allowed' : 'pointer', opacity: disabled ? 0.6 : 1 }}>\n {label}\n </label>\n )}\n </div>\n {error && (\n <p role=\"alert\" style={{ marginTop: 4, fontSize: 12, color: '#dc2626' }}>\n {error}\n </p>\n )}\n {helperText && !error && <p style={{ marginTop: 4, fontSize: 12, color: '#6b7280' }}>{helperText}</p>}\n </div>\n )\n})\nCheckbox.displayName = 'Checkbox'\n\n// ---------------------------------------------------------------------------\n// Select (controlled; onChange receives the new value string)\n// ---------------------------------------------------------------------------\n\nexport type SelectSize = 'sm' | 'md' | 'lg'\n\nexport interface SelectOption {\n value: string\n label: string\n disabled?: boolean\n}\n\nexport interface SelectProps {\n options: SelectOption[]\n value?: string\n onChange?: (value: string) => void\n placeholder?: string\n label?: string\n error?: string\n helperText?: string\n size?: SelectSize\n disabled?: boolean\n fullWidth?: boolean\n className?: string\n id?: string\n name?: string\n 'aria-label'?: string\n}\n\n/**\n * Select — delegates to the platform's real (WAI-ARIA listbox) Select at render time.\n * The fallback is a native `<select>` — functionally equivalent, visually plainer.\n *\n * @example\n * <Select label=\"Environment\" value={env} onChange={setEnv} options={[{ value: 'prod', label: 'Production' }]} />\n */\nexport const Select: React.FC<SelectProps> = (props) => {\n const HostSelect = getHostUi<React.FC<SelectProps>>('Select')\n if (HostSelect) return <HostSelect {...props} />\n\n const { options, value, onChange, placeholder = 'Select…', label, error, helperText, disabled, fullWidth = true, id, name, className } = props\n const selectId = id ?? (label ? `vx-select-${label.toLowerCase().replace(/\\s+/g, '-')}` : undefined)\n\n return (\n <div className={className} style={{ ...fallbackNote, width: fullWidth ? '100%' : undefined }}>\n {label && (\n <label htmlFor={selectId} style={{ display: 'block', fontSize: 13, fontWeight: 500, marginBottom: 4 }}>\n {label}\n </label>\n )}\n <select\n id={selectId}\n name={name}\n aria-label={props['aria-label']}\n aria-invalid={!!error || undefined}\n disabled={disabled}\n value={value ?? ''}\n onChange={(event) => onChange?.(event.target.value)}\n style={{ width: '100%', padding: '6px 10px', borderRadius: 6, border: '1px solid #9ca3af' }}\n >\n {placeholder && (\n <option value=\"\" disabled>\n {placeholder}\n </option>\n )}\n {options.map((option) => (\n <option key={option.value} value={option.value} disabled={option.disabled}>\n {option.label}\n </option>\n ))}\n </select>\n {error && (\n <p role=\"alert\" style={{ marginTop: 4, fontSize: 12, color: '#dc2626' }}>\n {error}\n </p>\n )}\n {helperText && !error && <p style={{ marginTop: 4, fontSize: 12, color: '#6b7280' }}>{helperText}</p>}\n </div>\n )\n}\nSelect.displayName = 'Select'\n\n// ---------------------------------------------------------------------------\n// FormField — generic label + control + error/hint wrapper\n// ---------------------------------------------------------------------------\n\nexport interface FormFieldProps {\n label?: string\n htmlFor?: string\n error?: string\n hint?: string\n required?: boolean\n className?: string\n children: React.ReactNode\n}\n\n/**\n * FormField — wraps a custom control (not already self-labeling like Input/Select) with\n * the platform's label + error/hint visual language.\n *\n * @example\n * <FormField label=\"Allowed IP ranges\" htmlFor=\"cidrs\" hint=\"One CIDR block per line\">\n * <textarea id=\"cidrs\" />\n * </FormField>\n */\nexport const FormField: React.FC<FormFieldProps> = (props) => {\n const HostFormField = getHostUi<React.FC<FormFieldProps>>('FormField')\n if (HostFormField) return <HostFormField {...props} />\n\n const { label, htmlFor, error, hint, required, className, children } = props\n return (\n <div className={className} style={fallbackNote}>\n {label && (\n <label htmlFor={htmlFor} style={{ display: 'block', fontSize: 13, fontWeight: 500, marginBottom: 4 }}>\n {label}\n {required && (\n <span aria-hidden=\"true\" style={{ color: '#dc2626', marginLeft: 2 }}>\n *\n </span>\n )}\n </label>\n )}\n {children}\n {error && (\n <p role=\"alert\" style={{ marginTop: 4, fontSize: 12, color: '#dc2626' }}>\n {error}\n </p>\n )}\n {hint && !error && <p style={{ marginTop: 4, fontSize: 12, color: '#6b7280' }}>{hint}</p>}\n </div>\n )\n}\nFormField.displayName = 'FormField'\n\n// ---------------------------------------------------------------------------\n// Tabs\n// ---------------------------------------------------------------------------\n\nexport interface TabItem {\n key?: string\n label: string\n content: React.ReactNode\n disabled?: boolean\n}\n\nexport interface TabsProps {\n tabs: TabItem[]\n defaultActiveIndex?: number\n activeIndex?: number\n onTabChange?: (index: number) => void\n children?: React.ReactNode\n className?: string\n}\n\n/**\n * Tabs — delegates to the platform's real (WAI-ARIA tabs pattern) Tabs at render time.\n *\n * @example\n * <Tabs tabs={[{ key: 'indexes', label: 'Indexes', content: <IndexesPanel /> }]} />\n */\nexport const Tabs: React.FC<TabsProps> = (props) => {\n const HostTabs = getHostUi<React.FC<TabsProps>>('Tabs')\n if (HostTabs) return <HostTabs {...props} />\n\n const { tabs, defaultActiveIndex = 0, activeIndex, onTabChange, children, className } = props\n const [internalIndex, setInternalIndex] = React.useState(defaultActiveIndex)\n const isControlled = activeIndex !== undefined\n const currentIndex = isControlled ? activeIndex : internalIndex\n const activeTab = tabs[currentIndex]\n\n const selectTab = (index: number) => {\n if (tabs[index]?.disabled) return\n if (!isControlled) setInternalIndex(index)\n onTabChange?.(index)\n }\n\n return (\n <div className={className} style={fallbackNote}>\n <div role=\"tablist\" style={{ display: 'flex', gap: 4, borderBottom: '1px solid #d1d5db' }}>\n {tabs.map((tab, index) => (\n <button\n key={tab.key ?? index}\n type=\"button\"\n role=\"tab\"\n aria-selected={index === currentIndex}\n disabled={tab.disabled}\n onClick={() => selectTab(index)}\n style={{\n padding: '6px 12px',\n border: 'none',\n borderBottom: index === currentIndex ? '2px solid currentColor' : '2px solid transparent',\n background: 'transparent',\n cursor: tab.disabled ? 'not-allowed' : 'pointer',\n fontWeight: index === currentIndex ? 600 : 400,\n opacity: tab.disabled ? 0.5 : 1,\n }}\n >\n {tab.label}\n </button>\n ))}\n </div>\n <div role=\"tabpanel\" style={{ padding: 12 }}>\n {children || activeTab?.content}\n </div>\n </div>\n )\n}\nTabs.displayName = 'Tabs'\n\n// ---------------------------------------------------------------------------\n// EmptyState\n// ---------------------------------------------------------------------------\n\nexport interface EmptyStateProps {\n icon?: React.ReactNode\n title: string\n description?: string\n action?: React.ReactNode\n className?: string\n}\n\n/** EmptyState — delegates to the platform's real EmptyState at render time. */\nexport const EmptyState: React.FC<EmptyStateProps> = (props) => {\n const HostEmptyState = getHostUi<React.FC<EmptyStateProps>>('EmptyState')\n if (HostEmptyState) return <HostEmptyState {...props} />\n\n const { icon, title, description, action, className } = props\n return (\n <div className={className} style={{ ...fallbackNote, textAlign: 'center', padding: '32px 16px' }}>\n {icon && <div style={{ marginBottom: 12 }}>{icon}</div>}\n <p style={{ fontWeight: 600, marginBottom: description ? 4 : 0 }}>{title}</p>\n {description && <p style={{ fontSize: 13, color: '#6b7280', marginBottom: action ? 12 : 0 }}>{description}</p>}\n {action}\n </div>\n )\n}\nEmptyState.displayName = 'EmptyState'\n\n// ---------------------------------------------------------------------------\n// Skeleton (+ Text/Card)\n// ---------------------------------------------------------------------------\n\nexport type SkeletonVariant = 'text' | 'circular' | 'rectangular'\n\nexport interface SkeletonProps extends React.HTMLAttributes<HTMLDivElement> {\n variant?: SkeletonVariant\n width?: string | number\n height?: string | number\n animation?: 'pulse' | 'wave' | 'none'\n}\n\nconst skeletonRadius: Record<SkeletonVariant, number | string> = { text: 4, circular: '50%', rectangular: 8 }\n\n/** Skeleton — delegates to the platform's real Skeleton at render time. */\nexport const Skeleton: React.FC<SkeletonProps> = (props) => {\n const HostSkeleton = getHostUi<React.FC<SkeletonProps>>('Skeleton')\n if (HostSkeleton) return <HostSkeleton {...props} />\n\n const { variant = 'text', width, height, style, ...rest } = props\n return (\n <div\n aria-hidden=\"true\"\n style={{\n background: '#e5e7eb',\n borderRadius: skeletonRadius[variant],\n width: width ?? (variant === 'text' ? '100%' : undefined),\n height: height ?? (variant === 'text' ? 14 : undefined),\n ...style,\n }}\n {...rest}\n />\n )\n}\nSkeleton.displayName = 'Skeleton'\n\nexport interface SkeletonTextProps {\n lines?: number\n width?: string | number\n lastLineWidth?: string | number\n className?: string\n}\n\n/** SkeletonText — a multi-line text skeleton, delegating to the platform's real one. */\nexport const SkeletonText: React.FC<SkeletonTextProps> = (props) => {\n const HostSkeletonText = getHostUi<React.FC<SkeletonTextProps>>('SkeletonText')\n if (HostSkeletonText) return <HostSkeletonText {...props} />\n\n const { lines = 3, width = '100%', lastLineWidth = '80%', className } = props\n return (\n <div className={className} style={{ display: 'flex', flexDirection: 'column', gap: 8 }}>\n {Array.from({ length: lines }).map((_, index) => (\n <Skeleton key={index} variant=\"text\" width={index === lines - 1 ? lastLineWidth : width} />\n ))}\n </div>\n )\n}\nSkeletonText.displayName = 'SkeletonText'\n\nexport interface SkeletonCardProps {\n hasAvatar?: boolean\n hasActions?: boolean\n className?: string\n}\n\n/** SkeletonCard — a card-shaped skeleton, delegating to the platform's real one. */\nexport const SkeletonCard: React.FC<SkeletonCardProps> = (props) => {\n const HostSkeletonCard = getHostUi<React.FC<SkeletonCardProps>>('SkeletonCard')\n if (HostSkeletonCard) return <HostSkeletonCard {...props} />\n\n const { hasAvatar, hasActions, className } = props\n return (\n <div className={className} style={{ border: '1px solid #e5e7eb', borderRadius: 8, padding: 16 }}>\n <div style={{ display: 'flex', gap: 12 }}>\n {hasAvatar && <Skeleton variant=\"circular\" width={40} height={40} />}\n <div style={{ flex: 1 }}>\n <Skeleton variant=\"text\" width=\"60%\" />\n <div style={{ marginTop: 8 }}>\n <SkeletonText lines={2} />\n </div>\n </div>\n </div>\n {hasActions && (\n <div style={{ display: 'flex', gap: 8, marginTop: 12 }}>\n <Skeleton variant=\"rectangular\" width={72} height={30} />\n <Skeleton variant=\"rectangular\" width={72} height={30} />\n </div>\n )}\n </div>\n )\n}\nSkeletonCard.displayName = 'SkeletonCard'\n\n// ---------------------------------------------------------------------------\n// Tooltip\n// ---------------------------------------------------------------------------\n\nexport type TooltipPlacement = 'top' | 'bottom' | 'left' | 'right'\n\nexport interface TooltipProps {\n content?: React.ReactNode\n placement?: TooltipPlacement\n delayDuration?: number\n disabled?: boolean\n className?: string\n children: React.ReactNode\n}\n\n/**\n * Tooltip — delegates to the platform's real Tooltip at render time. The fallback uses the\n * browser's native `title` attribute (only works when `content` is plain text).\n */\nexport const Tooltip: React.FC<TooltipProps> = (props) => {\n const HostTooltip = getHostUi<React.FC<TooltipProps>>('Tooltip')\n if (HostTooltip) return <HostTooltip {...props} />\n\n const { content, disabled, className, children } = props\n const titleText = typeof content === 'string' ? content : undefined\n if (disabled || !titleText) return <>{children}</>\n return (\n <span className={className} title={titleText} style={{ display: 'inline-flex' }}>\n {children}\n </span>\n )\n}\nTooltip.displayName = 'Tooltip'\n\n// ---------------------------------------------------------------------------\n// Spinner\n// ---------------------------------------------------------------------------\n\nexport type SpinnerSize = 'sm' | 'md' | 'lg'\n\nexport interface SpinnerProps {\n size?: SpinnerSize\n className?: string\n label?: string\n}\n\nconst spinnerDiameter: Record<SpinnerSize, number> = { sm: 16, md: 24, lg: 32 }\n\n/** Spinner — delegates to the platform's real Spinner at render time. */\nexport const Spinner: React.FC<SpinnerProps> = (props) => {\n const HostSpinner = getHostUi<React.FC<SpinnerProps>>('Spinner')\n if (HostSpinner) return <HostSpinner {...props} />\n\n const { size = 'md', className, label } = props\n const diameter = spinnerDiameter[size]\n return (\n <div className={className} role=\"status\" aria-live=\"polite\" style={{ display: 'flex', flexDirection: 'column', alignItems: 'center' }}>\n <div\n aria-hidden=\"true\"\n style={{\n width: diameter,\n height: diameter,\n borderRadius: '50%',\n border: '2px solid currentColor',\n borderTopColor: 'transparent',\n animation: 'vx-sdk-spin 0.8s linear infinite',\n }}\n />\n {label && <p style={{ marginTop: 8, fontSize: 12, color: '#6b7280' }}>{label}</p>}\n <span style={{ position: 'absolute', width: 1, height: 1, overflow: 'hidden', clip: 'rect(0 0 0 0)' }}>{label || 'Loading'}</span>\n <style>{'@keyframes vx-sdk-spin { to { transform: rotate(360deg) } }'}</style>\n </div>\n )\n}\nSpinner.displayName = 'Spinner'\n\n// ---------------------------------------------------------------------------\n// DataTable (generic)\n// ---------------------------------------------------------------------------\n\nexport type DataTableAlign = 'left' | 'center' | 'right'\nexport type DataTableSortOrder = 'asc' | 'desc'\n\nexport interface DataTableSort {\n field: string\n order: DataTableSortOrder\n}\n\nexport interface DataTableColumn<T> {\n key: string\n header: React.ReactNode\n render?: (row: T) => React.ReactNode\n sortable?: boolean\n align?: DataTableAlign\n width?: string\n className?: string\n}\n\nexport interface DataTableEmptyState {\n icon?: React.ReactNode\n title: string\n description?: string\n action?: React.ReactNode\n}\n\nexport interface DataTablePaginationState {\n page: number\n pageSize: number\n total: number\n}\n\nexport interface DataTableProps<T> {\n columns: DataTableColumn<T>[]\n data: T[]\n rowKey: (row: T) => string\n isLoading?: boolean\n emptyState?: DataTableEmptyState\n sort?: DataTableSort\n onSortChange?: (sort: DataTableSort) => void\n pagination?: DataTablePaginationState\n onPageChange?: (page: number) => void\n onRowClick?: (row: T) => void\n rowActions?: (row: T) => React.ReactNode\n className?: string\n}\n\ntype DataTableComponent = (<T>(props: DataTableProps<T>) => React.ReactElement) & { displayName?: string }\n\nfunction FallbackDataTable<T>(props: DataTableProps<T>): React.ReactElement {\n const { columns, data, rowKey, isLoading, emptyState, onRowClick, rowActions, className } = props\n const showEmpty = !isLoading && data.length === 0\n\n return (\n <div className={className} style={fallbackNote}>\n <table style={{ width: '100%', borderCollapse: 'collapse' }}>\n <thead>\n <tr>\n {columns.map((column) => (\n <th key={column.key} style={{ textAlign: column.align ?? 'left', padding: '8px 10px', borderBottom: '1px solid #d1d5db' }}>\n {column.header}\n </th>\n ))}\n {rowActions && <th style={{ padding: '8px 10px', borderBottom: '1px solid #d1d5db' }} />}\n </tr>\n </thead>\n <tbody>\n {isLoading && (\n <tr>\n <td colSpan={Math.max(columns.length + (rowActions ? 1 : 0), 1)} style={{ padding: '12px 10px' }}>\n Loading…\n </td>\n </tr>\n )}\n {showEmpty && (\n <tr>\n <td colSpan={Math.max(columns.length + (rowActions ? 1 : 0), 1)}>\n <EmptyState title={emptyState?.title ?? 'No data'} description={emptyState?.description} icon={emptyState?.icon} action={emptyState?.action} />\n </td>\n </tr>\n )}\n {!isLoading &&\n !showEmpty &&\n data.map((row) => (\n <tr\n key={rowKey(row)}\n onClick={onRowClick ? () => onRowClick(row) : undefined}\n style={{ cursor: onRowClick ? 'pointer' : undefined, borderBottom: '1px solid #e5e7eb' }}\n >\n {columns.map((column) => (\n <td key={column.key} style={{ textAlign: column.align ?? 'left', padding: '8px 10px' }}>\n {column.render ? column.render(row) : String((row as Record<string, unknown>)[column.key] ?? '')}\n </td>\n ))}\n {rowActions && (\n <td style={{ padding: '8px 10px' }} onClick={(event) => event.stopPropagation()}>\n {rowActions(row)}\n </td>\n )}\n </tr>\n ))}\n </tbody>\n </table>\n </div>\n )\n}\n\n/**\n * DataTable — delegates to the platform's real, server-driven DataTable at render time.\n *\n * @example\n * <DataTable\n * columns={[{ key: 'name', header: 'Name' }, { key: 'deployState', header: 'Status', render: (r) => <Badge>{r.deployState}</Badge> }]}\n * data={indexes}\n * rowKey={(row) => row.id}\n * />\n */\nexport function DataTable<T>(props: DataTableProps<T>): React.ReactElement {\n const HostDataTable = getHostUi<DataTableComponent>('DataTable')\n if (HostDataTable) return <HostDataTable {...props} />\n return <FallbackDataTable {...props} />\n}\n\n// ---------------------------------------------------------------------------\n// StatsCard\n// ---------------------------------------------------------------------------\n\nexport type StatsCardVariant = 'default' | 'primary' | 'success' | 'warning' | 'danger' | 'info'\n\nexport interface StatsCardDelta {\n value: string\n direction: 'up' | 'down' | 'neutral'\n label?: string\n}\n\nexport interface StatsCardProps {\n label: string\n value: React.ReactNode\n icon?: React.ReactNode\n delta?: StatsCardDelta\n variant?: StatsCardVariant\n isLoading?: boolean\n onClick?: () => void\n className?: string\n}\n\nconst DELTA_FALLBACK_COLOR: Record<StatsCardDelta['direction'], string> = {\n up: '#16a34a',\n down: '#dc2626',\n neutral: '#6b7280',\n}\n\n/**\n * StatsCard — delegates to the platform's real StatsCard at render time.\n *\n * @example\n * <StatsCard label=\"Indexes\" value={indexes.length} delta={{ value: '+2', direction: 'up' }} />\n */\nexport const StatsCard: React.FC<StatsCardProps> = (props) => {\n const HostStatsCard = getHostUi<React.FC<StatsCardProps>>('StatsCard')\n if (HostStatsCard) return <HostStatsCard {...props} />\n\n const { label, value, icon, delta, isLoading, onClick, className } = props\n const isClickable = Boolean(onClick)\n\n return (\n <div\n role={isClickable ? 'button' : undefined}\n tabIndex={isClickable ? 0 : undefined}\n onClick={onClick}\n onKeyDown={\n isClickable\n ? (event) => {\n if (event.key === 'Enter' || event.key === ' ') {\n event.preventDefault()\n onClick?.()\n }\n }\n : undefined\n }\n className={className}\n style={{\n ...fallbackNote,\n border: '1px solid #d1d5db',\n borderRadius: 8,\n padding: 16,\n display: 'flex',\n alignItems: 'flex-start',\n justifyContent: 'space-between',\n gap: 12,\n cursor: isClickable ? 'pointer' : undefined,\n }}\n >\n <div style={{ minWidth: 0, flex: 1 }}>\n <p style={{ fontSize: 13, color: '#6b7280', margin: 0 }}>{label}</p>\n <p style={{ fontSize: 28, fontWeight: 700, margin: '4px 0 0' }}>{isLoading ? '…' : value}</p>\n {delta && !isLoading && (\n <p style={{ fontSize: 13, color: DELTA_FALLBACK_COLOR[delta.direction], margin: '4px 0 0' }}>\n {delta.value} {delta.label}\n </p>\n )}\n </div>\n {icon && <div aria-hidden=\"true\">{icon}</div>}\n </div>\n )\n}\nStatsCard.displayName = 'StatsCard'\n\n// ---------------------------------------------------------------------------\n// FormDialog\n// ---------------------------------------------------------------------------\n\nexport type FormDialogSize = 'sm' | 'md' | 'lg'\n\nexport interface FormDialogProps {\n isOpen: boolean\n onClose: () => void\n title: string\n description?: string\n children: React.ReactNode\n onSubmit: () => void | Promise<void>\n submitText?: string\n cancelText?: string\n isSubmitting?: boolean\n error?: string | null\n size?: FormDialogSize\n disableBackdropClose?: boolean\n submitDisabled?: boolean\n}\n\nconst FORM_DIALOG_MAX_WIDTH: Record<FormDialogSize, number> = { sm: 420, md: 520, lg: 680 }\n\n/**\n * FormDialog — delegates to the platform's real FormDialog at render time. The fallback is\n * a minimal, accessible modal shell (role=\"dialog\", Escape-to-close, backdrop click) without\n * the host's focus-trap polish.\n *\n * @example\n * <FormDialog isOpen={isOpen} onClose={close} title=\"Add index\" onSubmit={handleSubmit}>\n * <Input label=\"Name\" value={name} onChange={(e) => setName(e.target.value)} />\n * </FormDialog>\n */\nexport const FormDialog: React.FC<FormDialogProps> = (props) => {\n const HostFormDialog = getHostUi<React.FC<FormDialogProps>>('FormDialog')\n if (HostFormDialog) return <HostFormDialog {...props} />\n\n const {\n isOpen,\n onClose,\n title,\n description,\n children,\n onSubmit,\n submitText = 'Save',\n cancelText = 'Cancel',\n isSubmitting = false,\n error = null,\n size = 'md',\n disableBackdropClose = false,\n submitDisabled = false,\n } = props\n\n React.useEffect(() => {\n if (!isOpen) return\n const handleKeyDown = (event: KeyboardEvent) => {\n if (event.key === 'Escape' && !isSubmitting) onClose()\n }\n document.addEventListener('keydown', handleKeyDown)\n return () => document.removeEventListener('keydown', handleKeyDown)\n }, [isOpen, isSubmitting, onClose])\n\n if (!isOpen) return null\n\n const requestClose = () => {\n if (!isSubmitting) onClose()\n }\n\n return (\n <div\n style={{ position: 'fixed', inset: 0, background: 'rgba(0,0,0,0.5)', display: 'flex', alignItems: 'center', justifyContent: 'center', zIndex: 50 }}\n onClick={disableBackdropClose ? undefined : requestClose}\n >\n <div\n role=\"dialog\"\n aria-modal=\"true\"\n aria-label={title}\n style={{ background: 'white', color: 'black', borderRadius: 8, width: '100%', maxWidth: FORM_DIALOG_MAX_WIDTH[size], maxHeight: '80vh', overflow: 'auto', ...fallbackNote }}\n onClick={(event) => event.stopPropagation()}\n >\n <form\n onSubmit={(event) => {\n event.preventDefault()\n void onSubmit()\n }}\n >\n <div style={{ padding: 16, borderBottom: '1px solid #d1d5db' }}>\n <h3 style={{ margin: 0, fontSize: 16, fontWeight: 600 }}>{title}</h3>\n {description && <p style={{ margin: '4px 0 0', fontSize: 13, color: '#6b7280' }}>{description}</p>}\n </div>\n <div style={{ padding: 16, display: 'flex', flexDirection: 'column', gap: 12 }}>\n {error && (\n <p role=\"alert\" style={{ margin: 0, fontSize: 13, color: '#dc2626' }}>\n {error}\n </p>\n )}\n {children}\n </div>\n <div style={{ padding: 16, borderTop: '1px solid #d1d5db', display: 'flex', justifyContent: 'flex-end', gap: 8 }}>\n <Button type=\"button\" variant=\"secondary\" onClick={requestClose} disabled={isSubmitting}>\n {cancelText}\n </Button>\n <Button type=\"submit\" variant=\"primary\" isLoading={isSubmitting} disabled={submitDisabled}>\n {submitText}\n </Button>\n </div>\n </form>\n </div>\n </div>\n )\n}\nFormDialog.displayName = 'FormDialog'\n\n// ---------------------------------------------------------------------------\n// useToast / useConfirmDialog\n//\n// Unlike the components above, these are HOOKS the host backs with real React\n// context (ToastContext / ConfirmationDialogContext), whose providers the\n// platform's root App.tsx mounts around the entire tree — including app\n// pages, since they render inside the host's own React instance. So inside\n// Veltrix these resolve to the real, working implementation with no extra\n// wiring. Outside the platform (no host, or an older host) they degrade to a\n// safe, non-throwing fallback instead of crashing: `toast()` logs to the\n// console and `confirm()` resolves to `false` (fails closed — no destructive\n// action proceeds without an explicit user confirmation the fallback cannot\n// provide).\n// ---------------------------------------------------------------------------\n\nexport type ToastVariant = 'success' | 'error' | 'warning' | 'info'\n\nexport interface ToastOptions {\n variant?: ToastVariant\n duration?: number\n action?: { label: string; onClick: () => void }\n}\n\nexport interface Toast {\n id: string\n message: string\n variant: ToastVariant\n duration?: number\n action?: { label: string; onClick: () => void }\n}\n\nexport interface ToastContextValue {\n toasts: Toast[]\n toast: (message: string, options?: ToastOptions) => string\n success: (message: string, duration?: number) => string\n error: (message: string, duration?: number) => string\n warning: (message: string, duration?: number) => string\n info: (message: string, duration?: number) => string\n promise: <T>(\n promise: Promise<T>,\n messages: { loading: string; success: string | ((data: T) => string); error: string | ((error: unknown) => string) },\n ) => Promise<T>\n dismiss: (id: string) => void\n dismissAll: () => void\n}\n\nfunction fallbackToast(message: string, options?: ToastOptions): string {\n // eslint-disable-next-line no-console -- deliberate: this IS the fallback surface.\n console.warn(`[@veltrixsecops/app-sdk/ui] Toast (${options?.variant ?? 'info'}): ${message}`)\n return 'fallback-toast'\n}\n\nconst fallbackToastContext: ToastContextValue = {\n toasts: [],\n toast: fallbackToast,\n success: (message) => fallbackToast(message, { variant: 'success' }),\n error: (message) => fallbackToast(message, { variant: 'error' }),\n warning: (message) => fallbackToast(message, { variant: 'warning' }),\n info: (message) => fallbackToast(message, { variant: 'info' }),\n promise: (promise) => promise,\n dismiss: () => {},\n dismissAll: () => {},\n}\n\n/**\n * useToast — delegates to the platform's real toast system when running inside Veltrix.\n * Outside it, `toast()`/`success()`/etc. log to the console instead of throwing.\n *\n * @example\n * const toast = useToast()\n * toast.success('Index saved')\n */\nexport function useToast(): ToastContextValue {\n const hostUseToast = getHostUi<() => ToastContextValue>('useToast')\n // eslint-disable-next-line react-hooks/rules-of-hooks -- `hostUseToast` IS the real hook;\n // its presence is fixed for the app's lifetime (the host runtime installs once at boot),\n // so this never actually violates the \"same hooks every render\" invariant in practice.\n if (hostUseToast) return hostUseToast()\n return fallbackToastContext\n}\n\nexport type ConfirmationVariant = 'danger' | 'warning' | 'info'\n\nexport interface ConfirmationOptions {\n title: string\n message: string\n confirmText?: string\n cancelText?: string\n variant?: ConfirmationVariant\n}\n\nexport interface ConfirmationDialogContextValue {\n confirm: (options: ConfirmationOptions) => Promise<boolean>\n}\n\nconst fallbackConfirmationContext: ConfirmationDialogContextValue = {\n confirm: (options) => {\n // eslint-disable-next-line no-console -- deliberate: this IS the fallback surface.\n console.warn(\n `[@veltrixsecops/app-sdk/ui] ConfirmationDialog is only available inside the Veltrix platform — ` +\n `\"${options.title}\" auto-resolved to \"not confirmed\" (fail closed).`,\n )\n return Promise.resolve(false)\n },\n}\n\n/**\n * useConfirmDialog — delegates to the platform's real confirmation dialog when running\n * inside Veltrix. Outside it, `confirm()` resolves to `false` (fails closed) rather than\n * throwing, so a guarded destructive action simply never proceeds instead of crashing.\n *\n * @example\n * const { confirm } = useConfirmDialog()\n * if (await confirm({ title: 'Delete index', message: 'This cannot be undone.', variant: 'danger' })) {\n * await deleteIndex(id)\n * }\n */\nexport function useConfirmDialog(): ConfirmationDialogContextValue {\n const hostUseConfirmDialog = getHostUi<() => ConfirmationDialogContextValue>('useConfirmDialog')\n // eslint-disable-next-line react-hooks/rules-of-hooks -- see useToast's note above.\n if (hostUseConfirmDialog) return hostUseConfirmDialog()\n return fallbackConfirmationContext\n}\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../../src/ui/index.tsx"],"sourcesContent":["// ========================================================================\n// @veltrixsecops/app-sdk/ui — the platform's shared component library,\n// exposed to app client bundles.\n//\n// App pages import these instead of hand-rolling raw HTML, so pages render\n// themed inside the Veltrix design system (dark/light + tenant branding via\n// `var(--vx-*)`), consistent with the rest of the portal, and externalized —\n// zero bundle bloat, one React instance. This completes the \"predictable\n// shell, flexible body\" contract: the platform owns the components; apps\n// compose their page body from them.\n//\n// RUNTIME: every export here reads its real implementation off the host at\n// render time — globalThis.__VELTRIX_APP_RUNTIME__.ui.<Name>, populated by\n// the platform from components/shared/* (see\n// client/src/appRuntime/installHostRuntime.ts). At packaging time the CLI's\n// client bundler (and the platform's on-demand esbuild bundle routes) shim\n// the '@veltrixsecops/app-sdk/ui' specifier straight to that `ui` bag, so\n// this module's own render-time lookup only actually executes in\n// non-bundled contexts: local dev, unit tests, a bare `tsc --noEmit`, or\n// Storybook.\n//\n// FALLBACK CONTRACT: outside the platform (host runtime absent, or an older\n// host that predates a given component) every export here renders a\n// minimal, accessible, unstyled fallback instead of throwing — an app page\n// under test or local dev keeps working, just without platform theming.\n// Never throw on render.\n//\n// TYPE FIDELITY: prop types are copied from the platform's real components\n// in client/src/components/shared (see the ADR at\n// _ai_tasks/ui-package/2026-07-10/02_sdk_ui_subpath.md) so app-author\n// typechecking matches what actually renders inside Veltrix. Heavy composite\n// widgets (ConfigurationCanvas, VersionControl, Pipeline) stay out of scope —\n// they carry platform coupling a later phase may expose read-only versions\n// of; see the ADR's \"Non-goals\" section.\n//\n// EXPORTS: Button, Badge, Card (+ CardHeader/CardBody/CardFooter), Input,\n// Textarea, Checkbox, Select, SearchBox, Pagination, FilterBar, SortSelect,\n// FormField, Tabs, EmptyState, Skeleton (+ SkeletonText/SkeletonCard),\n// Tooltip, Spinner, DataTable, StatsCard, FormDialog, useToast,\n// useConfirmDialog.\n//\n// useToast / useConfirmDialog are included because the platform's root\n// App.tsx mounts ToastProvider/ConfirmationDialogProvider around the ENTIRE\n// tree (including every app page, since app pages render inside the host's\n// own React instance) — so the real context-backed hooks resolve correctly\n// from app code with no extra wiring. Outside the platform they degrade to a\n// safe, non-throwing fallback (see each hook's docs below) rather than\n// crashing or silently doing nothing.\n// ========================================================================\n\nimport * as React from 'react'\nimport { getHostRuntime } from '../client'\n\n/** Read one named component off the host's `runtime.ui` bag, or undefined. */\nfunction getHostUi<T>(name: string): T | undefined {\n return getHostRuntime()?.ui?.[name] as T | undefined\n}\n\nconst fallbackNote: React.CSSProperties = { fontFamily: 'inherit' }\n\n// ---------------------------------------------------------------------------\n// Button\n// ---------------------------------------------------------------------------\n\nexport type ButtonVariant = 'primary' | 'secondary' | 'danger' | 'success' | 'warning' | 'ghost' | 'link'\nexport type ButtonSize = 'sm' | 'md' | 'lg'\n\nexport interface ButtonProps extends React.ButtonHTMLAttributes<HTMLButtonElement> {\n variant?: ButtonVariant\n size?: ButtonSize\n isLoading?: boolean\n loadingText?: string\n fullWidth?: boolean\n leftIcon?: React.ReactNode\n rightIcon?: React.ReactNode\n}\n\ntype ButtonComponent = React.ForwardRefExoticComponent<ButtonProps & React.RefAttributes<HTMLButtonElement>>\n\n/**\n * Button — delegates to the platform's real Button at render time.\n *\n * @example\n * <Button variant=\"primary\" leftIcon={<RefreshIcon />} onClick={refresh}>Refresh</Button>\n */\nexport const Button = React.forwardRef<HTMLButtonElement, ButtonProps>((props, ref) => {\n const HostButton = getHostUi<ButtonComponent>('Button')\n if (HostButton) return <HostButton ref={ref} {...props} />\n\n const {\n variant: _variant,\n size: _size,\n isLoading,\n loadingText,\n fullWidth,\n leftIcon,\n rightIcon,\n children,\n disabled,\n type,\n style,\n ...rest\n } = props\n\n return (\n <button\n ref={ref}\n type={type ?? 'button'}\n disabled={disabled || isLoading}\n aria-busy={isLoading || undefined}\n style={{\n ...fallbackNote,\n display: 'inline-flex',\n alignItems: 'center',\n gap: 6,\n padding: '6px 14px',\n borderRadius: 6,\n border: '1px solid currentColor',\n background: 'transparent',\n cursor: disabled || isLoading ? 'not-allowed' : 'pointer',\n width: fullWidth ? '100%' : undefined,\n opacity: disabled || isLoading ? 0.6 : 1,\n justifyContent: 'center',\n ...style,\n }}\n {...rest}\n >\n {leftIcon}\n {isLoading ? loadingText ?? children : children}\n {rightIcon}\n </button>\n )\n})\nButton.displayName = 'Button'\n\n// ---------------------------------------------------------------------------\n// Badge\n// ---------------------------------------------------------------------------\n\nexport type BadgeVariant = 'default' | 'primary' | 'secondary' | 'success' | 'danger' | 'warning' | 'info'\nexport type BadgeSize = 'sm' | 'md' | 'lg'\n\nexport interface BadgeProps extends React.HTMLAttributes<HTMLSpanElement> {\n variant?: BadgeVariant\n size?: BadgeSize\n rounded?: boolean\n dot?: boolean\n}\n\nconst BADGE_FALLBACK_COLORS: Record<BadgeVariant, string> = {\n default: '#6b7280',\n primary: '#4f46e5',\n secondary: '#6b7280',\n success: '#16a34a',\n danger: '#dc2626',\n warning: '#d97706',\n info: '#0284c7',\n}\n\n/**\n * Badge — delegates to the platform's real Badge at render time.\n *\n * @example\n * <Badge variant={row.deployState === 'deployed' ? 'success' : 'warning'}>{row.deployState}</Badge>\n */\nexport const Badge: React.FC<BadgeProps> = ({ variant = 'default', size = 'md', rounded, dot, children, style, ...rest }) => {\n const HostBadge = getHostUi<React.FC<BadgeProps>>('Badge')\n if (HostBadge) return <HostBadge variant={variant} size={size} rounded={rounded} dot={dot} style={style} {...rest}>{children}</HostBadge>\n\n const color = BADGE_FALLBACK_COLORS[variant]\n const fontSize = size === 'sm' ? 11 : size === 'lg' ? 14 : 12\n return (\n <span\n style={{\n ...fallbackNote,\n display: 'inline-flex',\n alignItems: 'center',\n gap: 4,\n padding: size === 'sm' ? '1px 6px' : size === 'lg' ? '3px 10px' : '2px 8px',\n borderRadius: rounded ? 999 : 4,\n border: `1px solid ${color}`,\n color,\n fontSize,\n fontWeight: 500,\n ...style,\n }}\n {...rest}\n >\n {dot && <span aria-hidden=\"true\" style={{ width: 6, height: 6, borderRadius: '50%', background: color }} />}\n {children}\n </span>\n )\n}\nBadge.displayName = 'Badge'\n\n// ---------------------------------------------------------------------------\n// Card (+ Header/Body/Footer)\n// ---------------------------------------------------------------------------\n\nexport interface CardProps extends React.HTMLAttributes<HTMLDivElement> {\n variant?: 'default' | 'bordered' | 'elevated'\n padding?: 'none' | 'sm' | 'md' | 'lg'\n}\nexport interface CardHeaderProps extends React.HTMLAttributes<HTMLDivElement> {\n actions?: React.ReactNode\n}\nexport type CardBodyProps = React.HTMLAttributes<HTMLDivElement>\nexport interface CardFooterProps extends React.HTMLAttributes<HTMLDivElement> {\n variant?: 'default' | 'bordered'\n}\n\n/** Card — delegates to the platform's real Card at render time. */\nexport const Card: React.FC<CardProps> = ({ children, style, ...rest }) => {\n const HostCard = getHostUi<React.FC<CardProps>>('Card')\n if (HostCard) return <HostCard style={style} {...rest}>{children}</HostCard>\n return (\n <div style={{ ...fallbackNote, border: '1px solid #d1d5db', borderRadius: 8, overflow: 'hidden', ...style }} {...rest}>\n {children}\n </div>\n )\n}\nCard.displayName = 'Card'\n\n/** CardHeader — the header section of a Card, with optional trailing actions. */\nexport const CardHeader: React.FC<CardHeaderProps> = ({ actions, children, style, ...rest }) => {\n const HostCardHeader = getHostUi<React.FC<CardHeaderProps>>('CardHeader')\n if (HostCardHeader) return <HostCardHeader actions={actions} style={style} {...rest}>{children}</HostCardHeader>\n return (\n <div\n style={{\n ...fallbackNote,\n padding: '12px 16px',\n borderBottom: '1px solid #d1d5db',\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'space-between',\n gap: 12,\n ...style,\n }}\n {...rest}\n >\n <div style={{ flex: 1, minWidth: 0 }}>{children}</div>\n {actions && <div>{actions}</div>}\n </div>\n )\n}\nCardHeader.displayName = 'CardHeader'\n\n/** CardBody — the main content area of a Card. */\nexport const CardBody: React.FC<CardBodyProps> = ({ children, style, ...rest }) => {\n const HostCardBody = getHostUi<React.FC<CardBodyProps>>('CardBody')\n if (HostCardBody) return <HostCardBody style={style} {...rest}>{children}</HostCardBody>\n return (\n <div style={{ ...fallbackNote, padding: '12px 16px', ...style }} {...rest}>\n {children}\n </div>\n )\n}\nCardBody.displayName = 'CardBody'\n\n/** CardFooter — the footer section of a Card, typically for actions. */\nexport const CardFooter: React.FC<CardFooterProps> = ({ children, style, ...rest }) => {\n const HostCardFooter = getHostUi<React.FC<CardFooterProps>>('CardFooter')\n if (HostCardFooter) return <HostCardFooter style={style} {...rest}>{children}</HostCardFooter>\n return (\n <div style={{ ...fallbackNote, padding: '12px 16px', borderTop: '1px solid #d1d5db', ...style }} {...rest}>\n {children}\n </div>\n )\n}\nCardFooter.displayName = 'CardFooter'\n\n// ---------------------------------------------------------------------------\n// Input\n// ---------------------------------------------------------------------------\n\nexport type InputSize = 'sm' | 'md' | 'lg'\nexport type InputVariant = 'default' | 'error' | 'success'\n\nexport interface InputProps extends Omit<React.InputHTMLAttributes<HTMLInputElement>, 'size'> {\n label?: string\n error?: string\n helperText?: string\n leftIcon?: React.ReactNode\n rightIcon?: React.ReactNode\n variant?: InputVariant\n inputSize?: InputSize\n isSuccess?: boolean\n fullWidth?: boolean\n}\n\ntype InputComponent = React.ForwardRefExoticComponent<InputProps & React.RefAttributes<HTMLInputElement>>\n\n/**\n * Input — delegates to the platform's real Input at render time.\n *\n * @example\n * <Input label=\"Index name\" value={name} onChange={(e) => setName(e.target.value)} error={errors.name} />\n */\nexport const Input = React.forwardRef<HTMLInputElement, InputProps>((props, ref) => {\n const HostInput = getHostUi<InputComponent>('Input')\n if (HostInput) return <HostInput ref={ref} {...props} />\n\n const { label, error, helperText, leftIcon, rightIcon, fullWidth = true, id, style, ...rest } = props\n const inputId = id ?? (label ? `vx-input-${label.toLowerCase().replace(/\\s+/g, '-')}` : undefined)\n\n return (\n <div style={{ ...fallbackNote, width: fullWidth ? '100%' : undefined }}>\n {label && (\n <label htmlFor={inputId} style={{ display: 'block', fontSize: 13, fontWeight: 500, marginBottom: 4 }}>\n {label}\n </label>\n )}\n <div style={{ display: 'flex', alignItems: 'center', gap: 6 }}>\n {leftIcon}\n <input\n ref={ref}\n id={inputId}\n aria-invalid={!!error || undefined}\n style={{ flex: 1, padding: '6px 10px', borderRadius: 6, border: '1px solid #9ca3af', ...style }}\n {...rest}\n />\n {rightIcon}\n </div>\n {error && (\n <p role=\"alert\" style={{ marginTop: 4, fontSize: 12, color: '#dc2626' }}>\n {error}\n </p>\n )}\n {helperText && !error && <p style={{ marginTop: 4, fontSize: 12, color: '#6b7280' }}>{helperText}</p>}\n </div>\n )\n})\nInput.displayName = 'Input'\n\n// ---------------------------------------------------------------------------\n// Textarea\n// ---------------------------------------------------------------------------\n\nexport interface TextareaProps extends React.TextareaHTMLAttributes<HTMLTextAreaElement> {\n label?: string\n error?: string\n helperText?: string\n fullWidth?: boolean\n}\n\ntype TextareaComponent = React.ForwardRefExoticComponent<TextareaProps & React.RefAttributes<HTMLTextAreaElement>>\n\n/**\n * Textarea — delegates to the platform's real Textarea at render time.\n *\n * @example\n * <Textarea label=\"Description\" helperText=\"Markdown is supported.\" />\n */\nexport const Textarea = React.forwardRef<HTMLTextAreaElement, TextareaProps>((props, ref) => {\n const HostTextarea = getHostUi<TextareaComponent>('Textarea')\n if (HostTextarea) return <HostTextarea ref={ref} {...props} />\n\n const { label, error, helperText, fullWidth = true, id, rows = 4, style, ...rest } = props\n const textareaId = id ?? (label ? `vx-textarea-${label.toLowerCase().replace(/\\s+/g, '-')}` : undefined)\n\n return (\n <div style={{ ...fallbackNote, width: fullWidth ? '100%' : undefined }}>\n {label && (\n <label htmlFor={textareaId} style={{ display: 'block', fontSize: 13, fontWeight: 500, marginBottom: 4 }}>\n {label}\n </label>\n )}\n <textarea\n ref={ref}\n id={textareaId}\n rows={rows}\n aria-invalid={!!error || undefined}\n style={{ width: '100%', padding: '6px 10px', borderRadius: 6, border: '1px solid #9ca3af', ...style }}\n {...rest}\n />\n {error && (\n <p role=\"alert\" style={{ marginTop: 4, fontSize: 12, color: '#dc2626' }}>\n {error}\n </p>\n )}\n {helperText && !error && <p style={{ marginTop: 4, fontSize: 12, color: '#6b7280' }}>{helperText}</p>}\n </div>\n )\n})\nTextarea.displayName = 'Textarea'\n\n// ---------------------------------------------------------------------------\n// Checkbox\n// ---------------------------------------------------------------------------\n\nexport interface CheckboxProps extends Omit<React.InputHTMLAttributes<HTMLInputElement>, 'type'> {\n label?: React.ReactNode\n error?: string\n helperText?: string\n}\n\ntype CheckboxComponent = React.ForwardRefExoticComponent<CheckboxProps & React.RefAttributes<HTMLInputElement>>\n\n/**\n * Checkbox — delegates to the platform's real Checkbox at render time.\n *\n * @example\n * <Checkbox label=\"Enable drift detection\" checked={enabled} onChange={(e) => setEnabled(e.target.checked)} />\n */\nexport const Checkbox = React.forwardRef<HTMLInputElement, CheckboxProps>((props, ref) => {\n const HostCheckbox = getHostUi<CheckboxComponent>('Checkbox')\n if (HostCheckbox) return <HostCheckbox ref={ref} {...props} />\n\n const { label, error, helperText, id, disabled, ...rest } = props\n const generatedId = React.useId()\n const inputId = id ?? generatedId\n\n return (\n <div style={fallbackNote}>\n <div style={{ display: 'flex', alignItems: 'center', gap: 8 }}>\n <input ref={ref} id={inputId} type=\"checkbox\" disabled={disabled} aria-invalid={!!error || undefined} {...rest} />\n {label && (\n <label htmlFor={inputId} style={{ fontSize: 13, cursor: disabled ? 'not-allowed' : 'pointer', opacity: disabled ? 0.6 : 1 }}>\n {label}\n </label>\n )}\n </div>\n {error && (\n <p role=\"alert\" style={{ marginTop: 4, fontSize: 12, color: '#dc2626' }}>\n {error}\n </p>\n )}\n {helperText && !error && <p style={{ marginTop: 4, fontSize: 12, color: '#6b7280' }}>{helperText}</p>}\n </div>\n )\n})\nCheckbox.displayName = 'Checkbox'\n\n// ---------------------------------------------------------------------------\n// Select (controlled; onChange receives the new value string)\n// ---------------------------------------------------------------------------\n\nexport type SelectSize = 'sm' | 'md' | 'lg'\n\nexport interface SelectOption {\n value: string\n label: string\n disabled?: boolean\n}\n\nexport interface SelectProps {\n options: SelectOption[]\n value?: string\n onChange?: (value: string) => void\n placeholder?: string\n label?: string\n error?: string\n helperText?: string\n size?: SelectSize\n disabled?: boolean\n fullWidth?: boolean\n className?: string\n id?: string\n name?: string\n 'aria-label'?: string\n}\n\n/**\n * Select — delegates to the platform's real (WAI-ARIA listbox) Select at render time.\n * The fallback is a native `<select>` — functionally equivalent, visually plainer.\n *\n * @example\n * <Select label=\"Environment\" value={env} onChange={setEnv} options={[{ value: 'prod', label: 'Production' }]} />\n */\nexport const Select: React.FC<SelectProps> = (props) => {\n const HostSelect = getHostUi<React.FC<SelectProps>>('Select')\n if (HostSelect) return <HostSelect {...props} />\n\n const { options, value, onChange, placeholder = 'Select…', label, error, helperText, disabled, fullWidth = true, id, name, className } = props\n const selectId = id ?? (label ? `vx-select-${label.toLowerCase().replace(/\\s+/g, '-')}` : undefined)\n\n return (\n <div className={className} style={{ ...fallbackNote, width: fullWidth ? '100%' : undefined }}>\n {label && (\n <label htmlFor={selectId} style={{ display: 'block', fontSize: 13, fontWeight: 500, marginBottom: 4 }}>\n {label}\n </label>\n )}\n <select\n id={selectId}\n name={name}\n aria-label={props['aria-label']}\n aria-invalid={!!error || undefined}\n disabled={disabled}\n value={value ?? ''}\n onChange={(event) => onChange?.(event.target.value)}\n style={{ width: '100%', padding: '6px 10px', borderRadius: 6, border: '1px solid #9ca3af' }}\n >\n {placeholder && (\n <option value=\"\" disabled>\n {placeholder}\n </option>\n )}\n {options.map((option) => (\n <option key={option.value} value={option.value} disabled={option.disabled}>\n {option.label}\n </option>\n ))}\n </select>\n {error && (\n <p role=\"alert\" style={{ marginTop: 4, fontSize: 12, color: '#dc2626' }}>\n {error}\n </p>\n )}\n {helperText && !error && <p style={{ marginTop: 4, fontSize: 12, color: '#6b7280' }}>{helperText}</p>}\n </div>\n )\n}\nSelect.displayName = 'Select'\n\n// ---------------------------------------------------------------------------\n// SearchBox\n// ---------------------------------------------------------------------------\n\nexport type SearchBoxSize = 'sm' | 'md' | 'lg'\n\nexport interface SearchBoxProps {\n /** Controlled search text. */\n value: string\n /** Called with the new text — debounced by `debounceMs` when set. */\n onChange: (value: string) => void\n placeholder?: string\n disabled?: boolean\n size?: SearchBoxSize\n /** Debounces `onChange` by this many ms; omit (or `0`) to call on every keystroke. */\n debounceMs?: number\n className?: string\n 'aria-label'?: string\n}\n\n/**\n * SearchBox — delegates to the platform's real SearchBox at render time (leading search icon,\n * a clear button once there's text, optional debounce). The fallback is a bare\n * `<input type=\"search\">` wired straight to `value`/`onChange` — no icon, no debounce, no\n * clear button — but functionally sufficient for typing and clearing.\n *\n * @example\n * <SearchBox value={search} onChange={setSearch} placeholder=\"Search apps…\" debounceMs={250} />\n */\nexport const SearchBox: React.FC<SearchBoxProps> = (props) => {\n const HostSearchBox = getHostUi<React.FC<SearchBoxProps>>('SearchBox')\n if (HostSearchBox) return <HostSearchBox {...props} />\n\n const { value, onChange, placeholder, disabled, className, 'aria-label': ariaLabel } = props\n return (\n <input\n type=\"search\"\n value={value}\n onChange={(event) => onChange(event.target.value)}\n placeholder={placeholder}\n disabled={disabled}\n aria-label={ariaLabel ?? placeholder ?? 'Search'}\n className={className}\n style={{ ...fallbackNote, width: '100%', padding: '6px 10px', borderRadius: 6, border: '1px solid #9ca3af' }}\n />\n )\n}\nSearchBox.displayName = 'SearchBox'\n\n// ---------------------------------------------------------------------------\n// Pagination\n// ---------------------------------------------------------------------------\n\nexport interface PaginationProps {\n /** 1-based current page. */\n page: number\n pageSize: number\n totalItems: number\n onPageChange: (page: number) => void\n /** Renders a page-size selector when provided together with `pageSizeOptions`. */\n onPageSizeChange?: (size: number) => void\n pageSizeOptions?: number[]\n disabled?: boolean\n className?: string\n}\n\n/**\n * Pagination — delegates to the platform's real Pagination at render time: a \"Showing X–Y of\n * N\" summary, numbered pages with ellipsis for large ranges, an optional page-size Select, and\n * `aria-current=\"page\"` on the active page — visually consistent with DataTable's built-in\n * pagination footer. The fallback is a plain Prev/Next pair with \"page X of Y\" text.\n *\n * @example\n * <Pagination page={page} pageSize={20} totalItems={total} onPageChange={setPage} />\n */\nexport const Pagination: React.FC<PaginationProps> = (props) => {\n const HostPagination = getHostUi<React.FC<PaginationProps>>('Pagination')\n if (HostPagination) return <HostPagination {...props} />\n\n const { page, pageSize, totalItems, onPageChange, disabled, className } = props\n const pageCount = Math.max(1, Math.ceil(totalItems / pageSize))\n const canGoPrev = !disabled && page > 1\n const canGoNext = !disabled && page < pageCount\n\n return (\n <nav aria-label=\"Pagination\" className={className} style={{ ...fallbackNote, display: 'flex', alignItems: 'center', gap: 12 }}>\n <button type=\"button\" onClick={() => onPageChange(page - 1)} disabled={!canGoPrev} style={{ padding: '4px 10px' }}>\n Prev\n </button>\n <span>\n page {page} of {pageCount}\n </span>\n <button type=\"button\" onClick={() => onPageChange(page + 1)} disabled={!canGoNext} style={{ padding: '4px 10px' }}>\n Next\n </button>\n </nav>\n )\n}\nPagination.displayName = 'Pagination'\n\n// ---------------------------------------------------------------------------\n// FilterBar\n// ---------------------------------------------------------------------------\n\nexport interface FilterOption {\n value: string\n label: string\n}\n\nexport interface FilterDefinition {\n /** Stable identifier; also the React key for this filter's dropdown. */\n key: string\n /** Shown as the dropdown's placeholder/aria-label, and as its entry in the \"Add filter\" menu. */\n label: string\n options: FilterOption[]\n /** `null` (not `''`) represents \"no selection\" — the value FilterBar clears back to. */\n value: string | null\n onChange: (value: string | null) => void\n /** Always rendered when true. Omit/false to make this filter addable/removable via the \"Add filter\" menu. */\n alwaysVisible?: boolean\n}\n\nexport interface FilterBarSearchProps {\n value: string\n onChange: (value: string) => void\n placeholder?: string\n}\n\nexport interface FilterBarProps {\n filters: FilterDefinition[]\n /** Renders a SearchBox ahead of the filter dropdowns when provided. */\n search?: FilterBarSearchProps\n /**\n * Called by \"Clear all\" instead of FilterBar's own clearing logic. Omit it to let FilterBar\n * clear every filter with a value itself (`filter.onChange(null)` for each).\n */\n onClearAll?: () => void\n addFilterLabel?: string\n className?: string\n}\n\n/**\n * FilterBar — delegates to the platform's real FilterBar at render time: an optional\n * SearchBox, always-visible filter dropdowns, and optional filters the user can add/remove via\n * an \"Add filter\" menu (a filter with a non-null `value` is always treated as visible, even\n * before the user explicitly adds it). The fallback renders every filter as a plain,\n * always-visible native `<select>` — no add/remove menu, no styled search box — so an app page\n * under test still exposes every filter's full behavior via `onChange`.\n *\n * @example\n * <FilterBar\n * search={{ value: search, onChange: setSearch, placeholder: 'Search apps…' }}\n * filters={[\n * { key: 'vendor', label: 'Vendor', options: vendorOptions, value: vendor, onChange: setVendor, alwaysVisible: true },\n * { key: 'category', label: 'Category', options: categoryOptions, value: category, onChange: setCategory },\n * ]}\n * />\n */\nexport const FilterBar: React.FC<FilterBarProps> = (props) => {\n const HostFilterBar = getHostUi<React.FC<FilterBarProps>>('FilterBar')\n if (HostFilterBar) return <HostFilterBar {...props} />\n\n const { filters, search, className } = props\n return (\n <div className={className} style={{ ...fallbackNote, display: 'flex', flexWrap: 'wrap', gap: 8, alignItems: 'center' }}>\n {search && (\n <input\n type=\"search\"\n aria-label={search.placeholder ?? 'Search'}\n placeholder={search.placeholder}\n value={search.value}\n onChange={(event) => search.onChange(event.target.value)}\n style={{ padding: '6px 10px', borderRadius: 6, border: '1px solid #9ca3af' }}\n />\n )}\n {filters.map((filter) => (\n <label key={filter.key} style={{ display: 'flex', flexDirection: 'column', fontSize: 12 }}>\n {filter.label}\n <select\n aria-label={filter.label}\n value={filter.value ?? ''}\n onChange={(event) => filter.onChange(event.target.value === '' ? null : event.target.value)}\n style={{ padding: '6px 10px', borderRadius: 6, border: '1px solid #9ca3af' }}\n >\n <option value=\"\">{filter.label}</option>\n {filter.options.map((option) => (\n <option key={option.value} value={option.value}>\n {option.label}\n </option>\n ))}\n </select>\n </label>\n ))}\n </div>\n )\n}\nFilterBar.displayName = 'FilterBar'\n\n// ---------------------------------------------------------------------------\n// SortSelect\n// ---------------------------------------------------------------------------\n\nexport type SortDirection = 'asc' | 'desc'\n\nexport interface SortOption {\n value: string\n label: string\n}\n\nexport interface SortSelectProps {\n /** Sortable fields, e.g. `[{ value: 'name', label: 'Name' }, { value: 'updatedAt', label: 'Updated' }]`. */\n options: SortOption[]\n /** Selected field key. */\n value: string\n direction: SortDirection\n /** Called with the field and direction together, whichever one the interaction changed. */\n onChange: (value: string, direction: SortDirection) => void\n disabled?: boolean\n className?: string\n}\n\n/**\n * SortSelect — delegates to the platform's real SortSelect at render time: a labeled field\n * Select paired with an asc/desc direction toggle button, styled to sit in the same toolbar\n * row as FilterBar. The standalone sort control for list/card surfaces that aren't a\n * DataTable (which has its own column-header sort). The fallback is a native `<select>` for\n * the field plus a button that flips direction.\n *\n * @example\n * <SortSelect\n * options={[{ value: 'name', label: 'Name' }, { value: 'updatedAt', label: 'Last updated' }]}\n * value={sortField}\n * direction={sortDirection}\n * onChange={(field, direction) => { setSortField(field); setSortDirection(direction) }}\n * />\n */\nexport const SortSelect: React.FC<SortSelectProps> = (props) => {\n const HostSortSelect = getHostUi<React.FC<SortSelectProps>>('SortSelect')\n if (HostSortSelect) return <HostSortSelect {...props} />\n\n const { options, value, direction, onChange, disabled, className } = props\n const directionLabel = direction === 'asc' ? 'Sort ascending' : 'Sort descending'\n\n return (\n <div className={className} style={{ ...fallbackNote, display: 'flex', alignItems: 'center', gap: 6 }}>\n <select\n aria-label=\"Sort by\"\n value={value}\n disabled={disabled}\n onChange={(event) => onChange(event.target.value, direction)}\n style={{ padding: '6px 10px', borderRadius: 6, border: '1px solid #9ca3af' }}\n >\n {options.map((option) => (\n <option key={option.value} value={option.value}>\n {option.label}\n </option>\n ))}\n </select>\n <button\n type=\"button\"\n disabled={disabled}\n onClick={() => onChange(value, direction === 'asc' ? 'desc' : 'asc')}\n aria-label={directionLabel}\n style={{ padding: '4px 10px' }}\n >\n {direction === 'asc' ? '↑' : '↓'}\n </button>\n </div>\n )\n}\nSortSelect.displayName = 'SortSelect'\n\n// ---------------------------------------------------------------------------\n// FormField — generic label + control + error/hint wrapper\n// ---------------------------------------------------------------------------\n\nexport interface FormFieldProps {\n label?: string\n htmlFor?: string\n error?: string\n hint?: string\n required?: boolean\n className?: string\n children: React.ReactNode\n}\n\n/**\n * FormField — wraps a custom control (not already self-labeling like Input/Select) with\n * the platform's label + error/hint visual language.\n *\n * @example\n * <FormField label=\"Allowed IP ranges\" htmlFor=\"cidrs\" hint=\"One CIDR block per line\">\n * <textarea id=\"cidrs\" />\n * </FormField>\n */\nexport const FormField: React.FC<FormFieldProps> = (props) => {\n const HostFormField = getHostUi<React.FC<FormFieldProps>>('FormField')\n if (HostFormField) return <HostFormField {...props} />\n\n const { label, htmlFor, error, hint, required, className, children } = props\n return (\n <div className={className} style={fallbackNote}>\n {label && (\n <label htmlFor={htmlFor} style={{ display: 'block', fontSize: 13, fontWeight: 500, marginBottom: 4 }}>\n {label}\n {required && (\n <span aria-hidden=\"true\" style={{ color: '#dc2626', marginLeft: 2 }}>\n *\n </span>\n )}\n </label>\n )}\n {children}\n {error && (\n <p role=\"alert\" style={{ marginTop: 4, fontSize: 12, color: '#dc2626' }}>\n {error}\n </p>\n )}\n {hint && !error && <p style={{ marginTop: 4, fontSize: 12, color: '#6b7280' }}>{hint}</p>}\n </div>\n )\n}\nFormField.displayName = 'FormField'\n\n// ---------------------------------------------------------------------------\n// Tabs\n// ---------------------------------------------------------------------------\n\nexport interface TabItem {\n key?: string\n label: string\n content: React.ReactNode\n disabled?: boolean\n}\n\nexport interface TabsProps {\n tabs: TabItem[]\n defaultActiveIndex?: number\n activeIndex?: number\n onTabChange?: (index: number) => void\n children?: React.ReactNode\n className?: string\n}\n\n/**\n * Tabs — delegates to the platform's real (WAI-ARIA tabs pattern) Tabs at render time.\n *\n * @example\n * <Tabs tabs={[{ key: 'indexes', label: 'Indexes', content: <IndexesPanel /> }]} />\n */\nexport const Tabs: React.FC<TabsProps> = (props) => {\n const HostTabs = getHostUi<React.FC<TabsProps>>('Tabs')\n if (HostTabs) return <HostTabs {...props} />\n\n const { tabs, defaultActiveIndex = 0, activeIndex, onTabChange, children, className } = props\n const [internalIndex, setInternalIndex] = React.useState(defaultActiveIndex)\n const isControlled = activeIndex !== undefined\n const currentIndex = isControlled ? activeIndex : internalIndex\n const activeTab = tabs[currentIndex]\n\n const selectTab = (index: number) => {\n if (tabs[index]?.disabled) return\n if (!isControlled) setInternalIndex(index)\n onTabChange?.(index)\n }\n\n return (\n <div className={className} style={fallbackNote}>\n <div role=\"tablist\" style={{ display: 'flex', gap: 4, borderBottom: '1px solid #d1d5db' }}>\n {tabs.map((tab, index) => (\n <button\n key={tab.key ?? index}\n type=\"button\"\n role=\"tab\"\n aria-selected={index === currentIndex}\n disabled={tab.disabled}\n onClick={() => selectTab(index)}\n style={{\n padding: '6px 12px',\n border: 'none',\n borderBottom: index === currentIndex ? '2px solid currentColor' : '2px solid transparent',\n background: 'transparent',\n cursor: tab.disabled ? 'not-allowed' : 'pointer',\n fontWeight: index === currentIndex ? 600 : 400,\n opacity: tab.disabled ? 0.5 : 1,\n }}\n >\n {tab.label}\n </button>\n ))}\n </div>\n <div role=\"tabpanel\" style={{ padding: 12 }}>\n {children || activeTab?.content}\n </div>\n </div>\n )\n}\nTabs.displayName = 'Tabs'\n\n// ---------------------------------------------------------------------------\n// EmptyState\n// ---------------------------------------------------------------------------\n\nexport interface EmptyStateProps {\n icon?: React.ReactNode\n title: string\n description?: string\n action?: React.ReactNode\n className?: string\n}\n\n/** EmptyState — delegates to the platform's real EmptyState at render time. */\nexport const EmptyState: React.FC<EmptyStateProps> = (props) => {\n const HostEmptyState = getHostUi<React.FC<EmptyStateProps>>('EmptyState')\n if (HostEmptyState) return <HostEmptyState {...props} />\n\n const { icon, title, description, action, className } = props\n return (\n <div className={className} style={{ ...fallbackNote, textAlign: 'center', padding: '32px 16px' }}>\n {icon && <div style={{ marginBottom: 12 }}>{icon}</div>}\n <p style={{ fontWeight: 600, marginBottom: description ? 4 : 0 }}>{title}</p>\n {description && <p style={{ fontSize: 13, color: '#6b7280', marginBottom: action ? 12 : 0 }}>{description}</p>}\n {action}\n </div>\n )\n}\nEmptyState.displayName = 'EmptyState'\n\n// ---------------------------------------------------------------------------\n// Skeleton (+ Text/Card)\n// ---------------------------------------------------------------------------\n\nexport type SkeletonVariant = 'text' | 'circular' | 'rectangular'\n\nexport interface SkeletonProps extends React.HTMLAttributes<HTMLDivElement> {\n variant?: SkeletonVariant\n width?: string | number\n height?: string | number\n animation?: 'pulse' | 'wave' | 'none'\n}\n\nconst skeletonRadius: Record<SkeletonVariant, number | string> = { text: 4, circular: '50%', rectangular: 8 }\n\n/** Skeleton — delegates to the platform's real Skeleton at render time. */\nexport const Skeleton: React.FC<SkeletonProps> = (props) => {\n const HostSkeleton = getHostUi<React.FC<SkeletonProps>>('Skeleton')\n if (HostSkeleton) return <HostSkeleton {...props} />\n\n const { variant = 'text', width, height, style, ...rest } = props\n return (\n <div\n aria-hidden=\"true\"\n style={{\n background: '#e5e7eb',\n borderRadius: skeletonRadius[variant],\n width: width ?? (variant === 'text' ? '100%' : undefined),\n height: height ?? (variant === 'text' ? 14 : undefined),\n ...style,\n }}\n {...rest}\n />\n )\n}\nSkeleton.displayName = 'Skeleton'\n\nexport interface SkeletonTextProps {\n lines?: number\n width?: string | number\n lastLineWidth?: string | number\n className?: string\n}\n\n/** SkeletonText — a multi-line text skeleton, delegating to the platform's real one. */\nexport const SkeletonText: React.FC<SkeletonTextProps> = (props) => {\n const HostSkeletonText = getHostUi<React.FC<SkeletonTextProps>>('SkeletonText')\n if (HostSkeletonText) return <HostSkeletonText {...props} />\n\n const { lines = 3, width = '100%', lastLineWidth = '80%', className } = props\n return (\n <div className={className} style={{ display: 'flex', flexDirection: 'column', gap: 8 }}>\n {Array.from({ length: lines }).map((_, index) => (\n <Skeleton key={index} variant=\"text\" width={index === lines - 1 ? lastLineWidth : width} />\n ))}\n </div>\n )\n}\nSkeletonText.displayName = 'SkeletonText'\n\nexport interface SkeletonCardProps {\n hasAvatar?: boolean\n hasActions?: boolean\n className?: string\n}\n\n/** SkeletonCard — a card-shaped skeleton, delegating to the platform's real one. */\nexport const SkeletonCard: React.FC<SkeletonCardProps> = (props) => {\n const HostSkeletonCard = getHostUi<React.FC<SkeletonCardProps>>('SkeletonCard')\n if (HostSkeletonCard) return <HostSkeletonCard {...props} />\n\n const { hasAvatar, hasActions, className } = props\n return (\n <div className={className} style={{ border: '1px solid #e5e7eb', borderRadius: 8, padding: 16 }}>\n <div style={{ display: 'flex', gap: 12 }}>\n {hasAvatar && <Skeleton variant=\"circular\" width={40} height={40} />}\n <div style={{ flex: 1 }}>\n <Skeleton variant=\"text\" width=\"60%\" />\n <div style={{ marginTop: 8 }}>\n <SkeletonText lines={2} />\n </div>\n </div>\n </div>\n {hasActions && (\n <div style={{ display: 'flex', gap: 8, marginTop: 12 }}>\n <Skeleton variant=\"rectangular\" width={72} height={30} />\n <Skeleton variant=\"rectangular\" width={72} height={30} />\n </div>\n )}\n </div>\n )\n}\nSkeletonCard.displayName = 'SkeletonCard'\n\n// ---------------------------------------------------------------------------\n// Tooltip\n// ---------------------------------------------------------------------------\n\nexport type TooltipPlacement = 'top' | 'bottom' | 'left' | 'right'\n\nexport interface TooltipProps {\n content?: React.ReactNode\n placement?: TooltipPlacement\n delayDuration?: number\n disabled?: boolean\n className?: string\n children: React.ReactNode\n}\n\n/**\n * Tooltip — delegates to the platform's real Tooltip at render time. The fallback uses the\n * browser's native `title` attribute (only works when `content` is plain text).\n */\nexport const Tooltip: React.FC<TooltipProps> = (props) => {\n const HostTooltip = getHostUi<React.FC<TooltipProps>>('Tooltip')\n if (HostTooltip) return <HostTooltip {...props} />\n\n const { content, disabled, className, children } = props\n const titleText = typeof content === 'string' ? content : undefined\n if (disabled || !titleText) return <>{children}</>\n return (\n <span className={className} title={titleText} style={{ display: 'inline-flex' }}>\n {children}\n </span>\n )\n}\nTooltip.displayName = 'Tooltip'\n\n// ---------------------------------------------------------------------------\n// Spinner\n// ---------------------------------------------------------------------------\n\nexport type SpinnerSize = 'sm' | 'md' | 'lg'\n\nexport interface SpinnerProps {\n size?: SpinnerSize\n className?: string\n label?: string\n}\n\nconst spinnerDiameter: Record<SpinnerSize, number> = { sm: 16, md: 24, lg: 32 }\n\n/** Spinner — delegates to the platform's real Spinner at render time. */\nexport const Spinner: React.FC<SpinnerProps> = (props) => {\n const HostSpinner = getHostUi<React.FC<SpinnerProps>>('Spinner')\n if (HostSpinner) return <HostSpinner {...props} />\n\n const { size = 'md', className, label } = props\n const diameter = spinnerDiameter[size]\n return (\n <div className={className} role=\"status\" aria-live=\"polite\" style={{ display: 'flex', flexDirection: 'column', alignItems: 'center' }}>\n <div\n aria-hidden=\"true\"\n style={{\n width: diameter,\n height: diameter,\n borderRadius: '50%',\n border: '2px solid currentColor',\n borderTopColor: 'transparent',\n animation: 'vx-sdk-spin 0.8s linear infinite',\n }}\n />\n {label && <p style={{ marginTop: 8, fontSize: 12, color: '#6b7280' }}>{label}</p>}\n <span style={{ position: 'absolute', width: 1, height: 1, overflow: 'hidden', clip: 'rect(0 0 0 0)' }}>{label || 'Loading'}</span>\n <style>{'@keyframes vx-sdk-spin { to { transform: rotate(360deg) } }'}</style>\n </div>\n )\n}\nSpinner.displayName = 'Spinner'\n\n// ---------------------------------------------------------------------------\n// DataTable (generic)\n// ---------------------------------------------------------------------------\n\nexport type DataTableAlign = 'left' | 'center' | 'right'\nexport type DataTableSortOrder = 'asc' | 'desc'\n\nexport interface DataTableSort {\n field: string\n order: DataTableSortOrder\n}\n\nexport interface DataTableColumn<T> {\n key: string\n header: React.ReactNode\n render?: (row: T) => React.ReactNode\n sortable?: boolean\n align?: DataTableAlign\n width?: string\n className?: string\n}\n\nexport interface DataTableEmptyState {\n icon?: React.ReactNode\n title: string\n description?: string\n action?: React.ReactNode\n}\n\nexport interface DataTablePaginationState {\n page: number\n pageSize: number\n total: number\n}\n\nexport interface DataTableProps<T> {\n columns: DataTableColumn<T>[]\n data: T[]\n rowKey: (row: T) => string\n isLoading?: boolean\n emptyState?: DataTableEmptyState\n sort?: DataTableSort\n onSortChange?: (sort: DataTableSort) => void\n pagination?: DataTablePaginationState\n onPageChange?: (page: number) => void\n onRowClick?: (row: T) => void\n rowActions?: (row: T) => React.ReactNode\n className?: string\n}\n\ntype DataTableComponent = (<T>(props: DataTableProps<T>) => React.ReactElement) & { displayName?: string }\n\nfunction FallbackDataTable<T>(props: DataTableProps<T>): React.ReactElement {\n const { columns, data, rowKey, isLoading, emptyState, onRowClick, rowActions, className } = props\n const showEmpty = !isLoading && data.length === 0\n\n return (\n <div className={className} style={fallbackNote}>\n <table style={{ width: '100%', borderCollapse: 'collapse' }}>\n <thead>\n <tr>\n {columns.map((column) => (\n <th key={column.key} style={{ textAlign: column.align ?? 'left', padding: '8px 10px', borderBottom: '1px solid #d1d5db' }}>\n {column.header}\n </th>\n ))}\n {rowActions && <th style={{ padding: '8px 10px', borderBottom: '1px solid #d1d5db' }} />}\n </tr>\n </thead>\n <tbody>\n {isLoading && (\n <tr>\n <td colSpan={Math.max(columns.length + (rowActions ? 1 : 0), 1)} style={{ padding: '12px 10px' }}>\n Loading…\n </td>\n </tr>\n )}\n {showEmpty && (\n <tr>\n <td colSpan={Math.max(columns.length + (rowActions ? 1 : 0), 1)}>\n <EmptyState title={emptyState?.title ?? 'No data'} description={emptyState?.description} icon={emptyState?.icon} action={emptyState?.action} />\n </td>\n </tr>\n )}\n {!isLoading &&\n !showEmpty &&\n data.map((row) => (\n <tr\n key={rowKey(row)}\n onClick={onRowClick ? () => onRowClick(row) : undefined}\n style={{ cursor: onRowClick ? 'pointer' : undefined, borderBottom: '1px solid #e5e7eb' }}\n >\n {columns.map((column) => (\n <td key={column.key} style={{ textAlign: column.align ?? 'left', padding: '8px 10px' }}>\n {column.render ? column.render(row) : String((row as Record<string, unknown>)[column.key] ?? '')}\n </td>\n ))}\n {rowActions && (\n <td style={{ padding: '8px 10px' }} onClick={(event) => event.stopPropagation()}>\n {rowActions(row)}\n </td>\n )}\n </tr>\n ))}\n </tbody>\n </table>\n </div>\n )\n}\n\n/**\n * DataTable — delegates to the platform's real, server-driven DataTable at render time.\n *\n * @example\n * <DataTable\n * columns={[{ key: 'name', header: 'Name' }, { key: 'deployState', header: 'Status', render: (r) => <Badge>{r.deployState}</Badge> }]}\n * data={indexes}\n * rowKey={(row) => row.id}\n * />\n */\nexport function DataTable<T>(props: DataTableProps<T>): React.ReactElement {\n const HostDataTable = getHostUi<DataTableComponent>('DataTable')\n if (HostDataTable) return <HostDataTable {...props} />\n return <FallbackDataTable {...props} />\n}\n\n// ---------------------------------------------------------------------------\n// StatsCard\n// ---------------------------------------------------------------------------\n\nexport type StatsCardVariant = 'default' | 'primary' | 'success' | 'warning' | 'danger' | 'info'\n\nexport interface StatsCardDelta {\n value: string\n direction: 'up' | 'down' | 'neutral'\n label?: string\n}\n\nexport interface StatsCardProps {\n label: string\n value: React.ReactNode\n icon?: React.ReactNode\n delta?: StatsCardDelta\n variant?: StatsCardVariant\n isLoading?: boolean\n onClick?: () => void\n className?: string\n}\n\nconst DELTA_FALLBACK_COLOR: Record<StatsCardDelta['direction'], string> = {\n up: '#16a34a',\n down: '#dc2626',\n neutral: '#6b7280',\n}\n\n/**\n * StatsCard — delegates to the platform's real StatsCard at render time.\n *\n * @example\n * <StatsCard label=\"Indexes\" value={indexes.length} delta={{ value: '+2', direction: 'up' }} />\n */\nexport const StatsCard: React.FC<StatsCardProps> = (props) => {\n const HostStatsCard = getHostUi<React.FC<StatsCardProps>>('StatsCard')\n if (HostStatsCard) return <HostStatsCard {...props} />\n\n const { label, value, icon, delta, isLoading, onClick, className } = props\n const isClickable = Boolean(onClick)\n\n return (\n <div\n role={isClickable ? 'button' : undefined}\n tabIndex={isClickable ? 0 : undefined}\n onClick={onClick}\n onKeyDown={\n isClickable\n ? (event) => {\n if (event.key === 'Enter' || event.key === ' ') {\n event.preventDefault()\n onClick?.()\n }\n }\n : undefined\n }\n className={className}\n style={{\n ...fallbackNote,\n border: '1px solid #d1d5db',\n borderRadius: 8,\n padding: 16,\n display: 'flex',\n alignItems: 'flex-start',\n justifyContent: 'space-between',\n gap: 12,\n cursor: isClickable ? 'pointer' : undefined,\n }}\n >\n <div style={{ minWidth: 0, flex: 1 }}>\n <p style={{ fontSize: 13, color: '#6b7280', margin: 0 }}>{label}</p>\n <p style={{ fontSize: 28, fontWeight: 700, margin: '4px 0 0' }}>{isLoading ? '…' : value}</p>\n {delta && !isLoading && (\n <p style={{ fontSize: 13, color: DELTA_FALLBACK_COLOR[delta.direction], margin: '4px 0 0' }}>\n {delta.value} {delta.label}\n </p>\n )}\n </div>\n {icon && <div aria-hidden=\"true\">{icon}</div>}\n </div>\n )\n}\nStatsCard.displayName = 'StatsCard'\n\n// ---------------------------------------------------------------------------\n// FormDialog\n// ---------------------------------------------------------------------------\n\nexport type FormDialogSize = 'sm' | 'md' | 'lg'\n\nexport interface FormDialogProps {\n isOpen: boolean\n onClose: () => void\n title: string\n description?: string\n children: React.ReactNode\n onSubmit: () => void | Promise<void>\n submitText?: string\n cancelText?: string\n isSubmitting?: boolean\n error?: string | null\n size?: FormDialogSize\n disableBackdropClose?: boolean\n submitDisabled?: boolean\n}\n\nconst FORM_DIALOG_MAX_WIDTH: Record<FormDialogSize, number> = { sm: 420, md: 520, lg: 680 }\n\n/**\n * FormDialog — delegates to the platform's real FormDialog at render time. The fallback is\n * a minimal, accessible modal shell (role=\"dialog\", Escape-to-close, backdrop click) without\n * the host's focus-trap polish.\n *\n * @example\n * <FormDialog isOpen={isOpen} onClose={close} title=\"Add index\" onSubmit={handleSubmit}>\n * <Input label=\"Name\" value={name} onChange={(e) => setName(e.target.value)} />\n * </FormDialog>\n */\nexport const FormDialog: React.FC<FormDialogProps> = (props) => {\n const HostFormDialog = getHostUi<React.FC<FormDialogProps>>('FormDialog')\n if (HostFormDialog) return <HostFormDialog {...props} />\n\n const {\n isOpen,\n onClose,\n title,\n description,\n children,\n onSubmit,\n submitText = 'Save',\n cancelText = 'Cancel',\n isSubmitting = false,\n error = null,\n size = 'md',\n disableBackdropClose = false,\n submitDisabled = false,\n } = props\n\n React.useEffect(() => {\n if (!isOpen) return\n const handleKeyDown = (event: KeyboardEvent) => {\n if (event.key === 'Escape' && !isSubmitting) onClose()\n }\n document.addEventListener('keydown', handleKeyDown)\n return () => document.removeEventListener('keydown', handleKeyDown)\n }, [isOpen, isSubmitting, onClose])\n\n if (!isOpen) return null\n\n const requestClose = () => {\n if (!isSubmitting) onClose()\n }\n\n return (\n <div\n style={{ position: 'fixed', inset: 0, background: 'rgba(0,0,0,0.5)', display: 'flex', alignItems: 'center', justifyContent: 'center', zIndex: 50 }}\n onClick={disableBackdropClose ? undefined : requestClose}\n >\n <div\n role=\"dialog\"\n aria-modal=\"true\"\n aria-label={title}\n style={{ background: 'white', color: 'black', borderRadius: 8, width: '100%', maxWidth: FORM_DIALOG_MAX_WIDTH[size], maxHeight: '80vh', overflow: 'auto', ...fallbackNote }}\n onClick={(event) => event.stopPropagation()}\n >\n <form\n onSubmit={(event) => {\n event.preventDefault()\n void onSubmit()\n }}\n >\n <div style={{ padding: 16, borderBottom: '1px solid #d1d5db' }}>\n <h3 style={{ margin: 0, fontSize: 16, fontWeight: 600 }}>{title}</h3>\n {description && <p style={{ margin: '4px 0 0', fontSize: 13, color: '#6b7280' }}>{description}</p>}\n </div>\n <div style={{ padding: 16, display: 'flex', flexDirection: 'column', gap: 12 }}>\n {error && (\n <p role=\"alert\" style={{ margin: 0, fontSize: 13, color: '#dc2626' }}>\n {error}\n </p>\n )}\n {children}\n </div>\n <div style={{ padding: 16, borderTop: '1px solid #d1d5db', display: 'flex', justifyContent: 'flex-end', gap: 8 }}>\n <Button type=\"button\" variant=\"secondary\" onClick={requestClose} disabled={isSubmitting}>\n {cancelText}\n </Button>\n <Button type=\"submit\" variant=\"primary\" isLoading={isSubmitting} disabled={submitDisabled}>\n {submitText}\n </Button>\n </div>\n </form>\n </div>\n </div>\n )\n}\nFormDialog.displayName = 'FormDialog'\n\n// ---------------------------------------------------------------------------\n// useToast / useConfirmDialog\n//\n// Unlike the components above, these are HOOKS the host backs with real React\n// context (ToastContext / ConfirmationDialogContext), whose providers the\n// platform's root App.tsx mounts around the entire tree — including app\n// pages, since they render inside the host's own React instance. So inside\n// Veltrix these resolve to the real, working implementation with no extra\n// wiring. Outside the platform (no host, or an older host) they degrade to a\n// safe, non-throwing fallback instead of crashing: `toast()` logs to the\n// console and `confirm()` resolves to `false` (fails closed — no destructive\n// action proceeds without an explicit user confirmation the fallback cannot\n// provide).\n// ---------------------------------------------------------------------------\n\nexport type ToastVariant = 'success' | 'error' | 'warning' | 'info'\n\nexport interface ToastOptions {\n variant?: ToastVariant\n duration?: number\n action?: { label: string; onClick: () => void }\n}\n\nexport interface Toast {\n id: string\n message: string\n variant: ToastVariant\n duration?: number\n action?: { label: string; onClick: () => void }\n}\n\nexport interface ToastContextValue {\n toasts: Toast[]\n toast: (message: string, options?: ToastOptions) => string\n success: (message: string, duration?: number) => string\n error: (message: string, duration?: number) => string\n warning: (message: string, duration?: number) => string\n info: (message: string, duration?: number) => string\n promise: <T>(\n promise: Promise<T>,\n messages: { loading: string; success: string | ((data: T) => string); error: string | ((error: unknown) => string) },\n ) => Promise<T>\n dismiss: (id: string) => void\n dismissAll: () => void\n}\n\nfunction fallbackToast(message: string, options?: ToastOptions): string {\n // eslint-disable-next-line no-console -- deliberate: this IS the fallback surface.\n console.warn(`[@veltrixsecops/app-sdk/ui] Toast (${options?.variant ?? 'info'}): ${message}`)\n return 'fallback-toast'\n}\n\nconst fallbackToastContext: ToastContextValue = {\n toasts: [],\n toast: fallbackToast,\n success: (message) => fallbackToast(message, { variant: 'success' }),\n error: (message) => fallbackToast(message, { variant: 'error' }),\n warning: (message) => fallbackToast(message, { variant: 'warning' }),\n info: (message) => fallbackToast(message, { variant: 'info' }),\n promise: (promise) => promise,\n dismiss: () => {},\n dismissAll: () => {},\n}\n\n/**\n * useToast — delegates to the platform's real toast system when running inside Veltrix.\n * Outside it, `toast()`/`success()`/etc. log to the console instead of throwing.\n *\n * @example\n * const toast = useToast()\n * toast.success('Index saved')\n */\nexport function useToast(): ToastContextValue {\n const hostUseToast = getHostUi<() => ToastContextValue>('useToast')\n // eslint-disable-next-line react-hooks/rules-of-hooks -- `hostUseToast` IS the real hook;\n // its presence is fixed for the app's lifetime (the host runtime installs once at boot),\n // so this never actually violates the \"same hooks every render\" invariant in practice.\n if (hostUseToast) return hostUseToast()\n return fallbackToastContext\n}\n\nexport type ConfirmationVariant = 'danger' | 'warning' | 'info'\n\nexport interface ConfirmationOptions {\n title: string\n message: string\n confirmText?: string\n cancelText?: string\n variant?: ConfirmationVariant\n}\n\nexport interface ConfirmationDialogContextValue {\n confirm: (options: ConfirmationOptions) => Promise<boolean>\n}\n\nconst fallbackConfirmationContext: ConfirmationDialogContextValue = {\n confirm: (options) => {\n // eslint-disable-next-line no-console -- deliberate: this IS the fallback surface.\n console.warn(\n `[@veltrixsecops/app-sdk/ui] ConfirmationDialog is only available inside the Veltrix platform — ` +\n `\"${options.title}\" auto-resolved to \"not confirmed\" (fail closed).`,\n )\n return Promise.resolve(false)\n },\n}\n\n/**\n * useConfirmDialog — delegates to the platform's real confirmation dialog when running\n * inside Veltrix. Outside it, `confirm()` resolves to `false` (fails closed) rather than\n * throwing, so a guarded destructive action simply never proceeds instead of crashing.\n *\n * @example\n * const { confirm } = useConfirmDialog()\n * if (await confirm({ title: 'Delete index', message: 'This cannot be undone.', variant: 'danger' })) {\n * await deleteIndex(id)\n * }\n */\nexport function useConfirmDialog(): ConfirmationDialogContextValue {\n const hostUseConfirmDialog = getHostUi<() => ConfirmationDialogContextValue>('useConfirmDialog')\n // eslint-disable-next-line react-hooks/rules-of-hooks -- see useToast's note above.\n if (hostUseConfirmDialog) return hostUseConfirmDialog()\n return fallbackConfirmationContext\n}\n"],"mappings":"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","names":[]}
|
|
@@ -365,6 +365,34 @@ interface Customer {
|
|
|
365
365
|
domain: string | null;
|
|
366
366
|
isActive: boolean;
|
|
367
367
|
}
|
|
368
|
+
/** One resolved permission entry the signed-in user's role grants. */
|
|
369
|
+
interface PermissionEntry {
|
|
370
|
+
resource: string;
|
|
371
|
+
action: string;
|
|
372
|
+
/** null = platform-scoped; a real App.id = scoped to that app. */
|
|
373
|
+
appId: string | null;
|
|
374
|
+
}
|
|
375
|
+
interface PermissionCheckOptions {
|
|
376
|
+
/**
|
|
377
|
+
* App-scoped check target. On `AppContextValue.permissions.has()` this
|
|
378
|
+
* defaults to the CURRENT app's own id when omitted (apps check their own
|
|
379
|
+
* declared resources by default) — pass `null` explicitly for a platform
|
|
380
|
+
* resource, or another app's id to check a different app. On the
|
|
381
|
+
* top-level `VeltrixHostRuntime.permissions.has()` there is no such
|
|
382
|
+
* default (omit for a platform-scoped check).
|
|
383
|
+
*/
|
|
384
|
+
appId?: string | null;
|
|
385
|
+
}
|
|
386
|
+
/**
|
|
387
|
+
* Permission-check surface. `has()` is fail-closed: `false` for anything
|
|
388
|
+
* not explicitly granted (including `all:all`/`resource:all` wildcards and
|
|
389
|
+
* the platform-admin bypass — all resolved server-side, mirrored client-side
|
|
390
|
+
* exactly).
|
|
391
|
+
*/
|
|
392
|
+
interface AppPermissionsApi {
|
|
393
|
+
has: (resource: string, action: string, opts?: PermissionCheckOptions) => boolean;
|
|
394
|
+
list: () => PermissionEntry[];
|
|
395
|
+
}
|
|
368
396
|
/**
|
|
369
397
|
* Loosely-typed handle to the platform database, passed to lifecycle hooks.
|
|
370
398
|
* At runtime this is the platform's Prisma client; model delegates are
|
|
@@ -418,6 +446,13 @@ interface AppContextValue {
|
|
|
418
446
|
settings: Record<string, unknown>;
|
|
419
447
|
/** The app's manifest branding, resolved by the platform (null when unset). */
|
|
420
448
|
branding?: AppBrandingDeclaration | null;
|
|
449
|
+
/**
|
|
450
|
+
* Permission checks for THIS app (RBAC/IdP hardening, Wave C4). `has()`
|
|
451
|
+
* without an explicit `opts.appId` checks the app's OWN declared
|
|
452
|
+
* resources by default. Prefer the `usePermissions()` hook
|
|
453
|
+
* (`@veltrixsecops/app-sdk/hooks`) over reaching into this directly.
|
|
454
|
+
*/
|
|
455
|
+
permissions: AppPermissionsApi;
|
|
421
456
|
}
|
|
422
457
|
declare const AppContext: Context<AppContextValue | null>;
|
|
423
458
|
/**
|
|
@@ -435,4 +470,4 @@ declare const AppContext: Context<AppContextValue | null>;
|
|
|
435
470
|
*/
|
|
436
471
|
declare function useAppContext(): AppContextValue;
|
|
437
472
|
|
|
438
|
-
export {
|
|
473
|
+
export { APP_PAGE_LAYOUTS as A, type InventoryItemInput as B, type Component as C, type PermissionEntry as D, type PlatformDatabaseClient as E, AppContext as F, useAppContext as G, type InventoryItem as I, type PermissionCheckOptions as P, type Tag as T, type User as U, APP_PAGE_NAV as a, type AppBrandingDeclaration as b, type AppConfigurationTypeManifest as c, type AppContextValue as d, type AppDetail as e, type AppHookContext as f, type AppInstallationDetail as g, type AppInstallationStatus as h, type AppListItem as i, type AppManifest as j, type AppPageDeclaration as k, type AppPageLayout as l, type AppPageNav as m, type AppPagePermission as n, type AppPermissionDeclaration as o, type AppPermissionsApi as p, type AppRouteContext as q, type AppSettingDeclaration as r, type AppSource as s, type AppStatusType as t, type Connectivity as u, type ConnectivityProviderRef as v, type Credential as w, type CredentialInput as x, type CredentialSummary as y, type Customer as z };
|
|
@@ -365,6 +365,34 @@ interface Customer {
|
|
|
365
365
|
domain: string | null;
|
|
366
366
|
isActive: boolean;
|
|
367
367
|
}
|
|
368
|
+
/** One resolved permission entry the signed-in user's role grants. */
|
|
369
|
+
interface PermissionEntry {
|
|
370
|
+
resource: string;
|
|
371
|
+
action: string;
|
|
372
|
+
/** null = platform-scoped; a real App.id = scoped to that app. */
|
|
373
|
+
appId: string | null;
|
|
374
|
+
}
|
|
375
|
+
interface PermissionCheckOptions {
|
|
376
|
+
/**
|
|
377
|
+
* App-scoped check target. On `AppContextValue.permissions.has()` this
|
|
378
|
+
* defaults to the CURRENT app's own id when omitted (apps check their own
|
|
379
|
+
* declared resources by default) — pass `null` explicitly for a platform
|
|
380
|
+
* resource, or another app's id to check a different app. On the
|
|
381
|
+
* top-level `VeltrixHostRuntime.permissions.has()` there is no such
|
|
382
|
+
* default (omit for a platform-scoped check).
|
|
383
|
+
*/
|
|
384
|
+
appId?: string | null;
|
|
385
|
+
}
|
|
386
|
+
/**
|
|
387
|
+
* Permission-check surface. `has()` is fail-closed: `false` for anything
|
|
388
|
+
* not explicitly granted (including `all:all`/`resource:all` wildcards and
|
|
389
|
+
* the platform-admin bypass — all resolved server-side, mirrored client-side
|
|
390
|
+
* exactly).
|
|
391
|
+
*/
|
|
392
|
+
interface AppPermissionsApi {
|
|
393
|
+
has: (resource: string, action: string, opts?: PermissionCheckOptions) => boolean;
|
|
394
|
+
list: () => PermissionEntry[];
|
|
395
|
+
}
|
|
368
396
|
/**
|
|
369
397
|
* Loosely-typed handle to the platform database, passed to lifecycle hooks.
|
|
370
398
|
* At runtime this is the platform's Prisma client; model delegates are
|
|
@@ -418,6 +446,13 @@ interface AppContextValue {
|
|
|
418
446
|
settings: Record<string, unknown>;
|
|
419
447
|
/** The app's manifest branding, resolved by the platform (null when unset). */
|
|
420
448
|
branding?: AppBrandingDeclaration | null;
|
|
449
|
+
/**
|
|
450
|
+
* Permission checks for THIS app (RBAC/IdP hardening, Wave C4). `has()`
|
|
451
|
+
* without an explicit `opts.appId` checks the app's OWN declared
|
|
452
|
+
* resources by default. Prefer the `usePermissions()` hook
|
|
453
|
+
* (`@veltrixsecops/app-sdk/hooks`) over reaching into this directly.
|
|
454
|
+
*/
|
|
455
|
+
permissions: AppPermissionsApi;
|
|
421
456
|
}
|
|
422
457
|
declare const AppContext: Context<AppContextValue | null>;
|
|
423
458
|
/**
|
|
@@ -435,4 +470,4 @@ declare const AppContext: Context<AppContextValue | null>;
|
|
|
435
470
|
*/
|
|
436
471
|
declare function useAppContext(): AppContextValue;
|
|
437
472
|
|
|
438
|
-
export {
|
|
473
|
+
export { APP_PAGE_LAYOUTS as A, type InventoryItemInput as B, type Component as C, type PermissionEntry as D, type PlatformDatabaseClient as E, AppContext as F, useAppContext as G, type InventoryItem as I, type PermissionCheckOptions as P, type Tag as T, type User as U, APP_PAGE_NAV as a, type AppBrandingDeclaration as b, type AppConfigurationTypeManifest as c, type AppContextValue as d, type AppDetail as e, type AppHookContext as f, type AppInstallationDetail as g, type AppInstallationStatus as h, type AppListItem as i, type AppManifest as j, type AppPageDeclaration as k, type AppPageLayout as l, type AppPageNav as m, type AppPagePermission as n, type AppPermissionDeclaration as o, type AppPermissionsApi as p, type AppRouteContext as q, type AppSettingDeclaration as r, type AppSource as s, type AppStatusType as t, type Connectivity as u, type ConnectivityProviderRef as v, type Credential as w, type CredentialInput as x, type CredentialSummary as y, type Customer as z };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@veltrixsecops/app-sdk",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.2.0",
|
|
4
4
|
"description": "Official SDK for building Veltrix Security-as-Code apps — typed pipeline handler contracts, lifecycle hook types, manifest types, and React hooks.",
|
|
5
5
|
"main": "dist/index.cjs",
|
|
6
6
|
"module": "dist/index.js",
|