@databricks/appkit-ui 0.47.0 → 0.48.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/cli/commands/lint.js +12 -5
- package/dist/cli/commands/lint.js.map +1 -1
- package/dist/react/index.d.ts +4 -1
- package/dist/react/index.js +3 -1
- package/dist/react/ui-variants/index.d.ts +2 -0
- package/dist/react/ui-variants/variant.d.ts +21 -0
- package/dist/react/ui-variants/variant.d.ts.map +1 -0
- package/dist/react/ui-variants/variant.js +15 -0
- package/dist/react/ui-variants/variant.js.map +1 -0
- package/dist/react/ui-variants/variants.d.ts +87 -0
- package/dist/react/ui-variants/variants.d.ts.map +1 -0
- package/dist/react/ui-variants/variants.js +199 -0
- package/dist/react/ui-variants/variants.js.map +1 -0
- package/dist/schemas/manifest.d.ts +1 -0
- package/dist/schemas/manifest.d.ts.map +1 -1
- package/dist/schemas/manifest.js +1 -0
- package/dist/schemas/manifest.js.map +1 -1
- package/dist/shared/src/plugin.d.ts.map +1 -1
- package/docs/api/appkit/Interface.PluginManifest.md +27 -9
- package/docs/plugins/manifest.md +12 -11
- package/package.json +1 -1
- package/sbom.cdx.json +1 -1
- package/scripts/postinstall.js +0 -1
|
@@ -26,10 +26,17 @@ const rules = [
|
|
|
26
26
|
id: "no-parse-float-without-validation",
|
|
27
27
|
pattern: "parseFloat($X).toFixed($Y)",
|
|
28
28
|
message: "parseFloat can return NaN. Validate input or use toNumber() helper from shared/types.ts."
|
|
29
|
+
},
|
|
30
|
+
{
|
|
31
|
+
id: "no-variants-in-prod",
|
|
32
|
+
pattern: "<Variants $$$P>$$$C</Variants>",
|
|
33
|
+
message: "<Variants> is a development-only variant picker and must not be shipped. Finalize the chosen <Variant> before deploying.",
|
|
34
|
+
includeTests: false
|
|
29
35
|
}
|
|
30
36
|
];
|
|
31
|
-
function isTestFile(filePath) {
|
|
32
|
-
|
|
37
|
+
function isTestFile(filePath, rootDir) {
|
|
38
|
+
const rel = path.relative(rootDir, filePath);
|
|
39
|
+
return /\.(test|spec)\.(ts|tsx)$/.test(rel) || /(^|[/\\])tests[/\\]/.test(rel);
|
|
33
40
|
}
|
|
34
41
|
function findTsFiles(dir, files = []) {
|
|
35
42
|
const entries = fs.readdirSync(dir, { withFileTypes: true });
|
|
@@ -47,11 +54,11 @@ function findTsFiles(dir, files = []) {
|
|
|
47
54
|
}
|
|
48
55
|
return files;
|
|
49
56
|
}
|
|
50
|
-
function lintFile(filePath, rules) {
|
|
57
|
+
function lintFile(filePath, rules, rootDir) {
|
|
51
58
|
const violations = [];
|
|
52
59
|
const content = fs.readFileSync(filePath, "utf-8");
|
|
53
60
|
const lang = filePath.endsWith(".tsx") ? Lang.Tsx : Lang.TypeScript;
|
|
54
|
-
const testFile = isTestFile(filePath);
|
|
61
|
+
const testFile = isTestFile(filePath, rootDir);
|
|
55
62
|
const root = parse(lang, content).root();
|
|
56
63
|
for (const rule of rules) {
|
|
57
64
|
if (testFile && rule.includeTests === false) continue;
|
|
@@ -81,7 +88,7 @@ function runLint() {
|
|
|
81
88
|
console.log(`Scanning ${files.length} TypeScript files...\n`);
|
|
82
89
|
const allViolations = [];
|
|
83
90
|
for (const file of files) {
|
|
84
|
-
const violations = lintFile(file, rules);
|
|
91
|
+
const violations = lintFile(file, rules, rootDir);
|
|
85
92
|
allViolations.push(...violations);
|
|
86
93
|
}
|
|
87
94
|
if (allViolations.length === 0) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"lint.js","names":[],"sources":["../../../src/cli/commands/lint.ts"],"sourcesContent":["import fs from \"node:fs\";\nimport path from \"node:path\";\nimport { Lang, parse } from \"@ast-grep/napi\";\nimport { Command } from \"commander\";\n\ninterface Rule {\n id: string;\n pattern: string;\n message: string;\n includeTests?: boolean;\n filter?: (code: string) => boolean;\n}\n\nconst rules: Rule[] = [\n {\n id: \"no-double-type-assertion\",\n pattern: \"$X as unknown as $Y\",\n message:\n \"Avoid double type assertion (as unknown as). Use proper type guards or fix the source type.\",\n },\n {\n id: \"no-as-any\",\n pattern: \"$X as any\",\n message:\n 'Avoid \"as any\" type assertion. Use proper typing or unknown with type guards.',\n includeTests: false, // acceptable in test mocks\n },\n {\n id: \"no-array-index-key\",\n pattern: \"key={$IDX}\",\n message:\n \"Avoid using array index as React key. Use a stable unique identifier.\",\n filter: (code) => /key=\\{(idx|index|i)\\}/.test(code),\n },\n {\n id: \"no-parse-float-without-validation\",\n pattern: \"parseFloat($X).toFixed($Y)\",\n message:\n \"parseFloat can return NaN. Validate input or use toNumber() helper from shared/types.ts.\",\n },\n];\n\nfunction isTestFile(filePath: string): boolean {\n return (\n /\\.(test|spec)\\.(ts|tsx)$/.test(
|
|
1
|
+
{"version":3,"file":"lint.js","names":[],"sources":["../../../src/cli/commands/lint.ts"],"sourcesContent":["import fs from \"node:fs\";\nimport path from \"node:path\";\nimport { Lang, parse } from \"@ast-grep/napi\";\nimport { Command } from \"commander\";\n\ninterface Rule {\n id: string;\n pattern: string;\n message: string;\n includeTests?: boolean;\n filter?: (code: string) => boolean;\n}\n\nconst rules: Rule[] = [\n {\n id: \"no-double-type-assertion\",\n pattern: \"$X as unknown as $Y\",\n message:\n \"Avoid double type assertion (as unknown as). Use proper type guards or fix the source type.\",\n },\n {\n id: \"no-as-any\",\n pattern: \"$X as any\",\n message:\n 'Avoid \"as any\" type assertion. Use proper typing or unknown with type guards.',\n includeTests: false, // acceptable in test mocks\n },\n {\n id: \"no-array-index-key\",\n pattern: \"key={$IDX}\",\n message:\n \"Avoid using array index as React key. Use a stable unique identifier.\",\n filter: (code) => /key=\\{(idx|index|i)\\}/.test(code),\n },\n {\n id: \"no-parse-float-without-validation\",\n pattern: \"parseFloat($X).toFixed($Y)\",\n message:\n \"parseFloat can return NaN. Validate input or use toNumber() helper from shared/types.ts.\",\n },\n {\n // <Variants> is the dev-only variant picker from @databricks/appkit-ui,\n // meant to drive the local edit loop. Finalize the chosen variant before\n // deploying so the picker chrome never reaches production.\n id: \"no-variants-in-prod\",\n pattern: \"<Variants $$$P>$$$C</Variants>\",\n message:\n \"<Variants> is a development-only variant picker and must not be shipped. Finalize the chosen <Variant> before deploying.\",\n includeTests: false,\n },\n];\n\nfunction isTestFile(filePath: string, rootDir: string): boolean {\n // Relative to scan root: an ancestor `tests` dir must not mark the whole project as tests.\n const rel = path.relative(rootDir, filePath);\n return (\n /\\.(test|spec)\\.(ts|tsx)$/.test(rel) || /(^|[/\\\\])tests[/\\\\]/.test(rel)\n );\n}\n\nfunction findTsFiles(dir: string, files: string[] = []): string[] {\n const entries = fs.readdirSync(dir, { withFileTypes: true });\n\n for (const entry of entries) {\n const fullPath = path.join(dir, entry.name);\n\n if (entry.isDirectory()) {\n if ([\"node_modules\", \"dist\", \"build\", \".git\"].includes(entry.name))\n continue;\n findTsFiles(fullPath, files);\n } else if (entry.isFile() && /\\.(ts|tsx)$/.test(entry.name)) {\n files.push(fullPath);\n }\n }\n\n return files;\n}\n\ninterface Violation {\n file: string;\n line: number;\n column: number;\n rule: string;\n message: string;\n code: string;\n}\n\nfunction lintFile(\n filePath: string,\n rules: Rule[],\n rootDir: string,\n): Violation[] {\n const violations: Violation[] = [];\n const content = fs.readFileSync(filePath, \"utf-8\");\n const lang = filePath.endsWith(\".tsx\") ? Lang.Tsx : Lang.TypeScript;\n const testFile = isTestFile(filePath, rootDir);\n\n const ast = parse(lang, content);\n const root = ast.root();\n\n for (const rule of rules) {\n // skip rules that don't apply to test files\n if (testFile && rule.includeTests === false) continue;\n\n const matches = root.findAll(rule.pattern);\n\n for (const match of matches) {\n const code = match.text();\n\n if (rule.filter && !rule.filter(code)) continue;\n\n const range = match.range();\n violations.push({\n file: filePath,\n line: range.start.line + 1,\n column: range.start.column + 1,\n rule: rule.id,\n message: rule.message,\n code: code.length > 80 ? `${code.slice(0, 77)}...` : code,\n });\n }\n }\n\n return violations;\n}\n\n/**\n * Lint command implementation\n */\nfunction runLint() {\n const rootDir = process.cwd();\n const files = findTsFiles(rootDir);\n\n console.log(`Scanning ${files.length} TypeScript files...\\n`);\n\n const allViolations: Violation[] = [];\n\n for (const file of files) {\n const violations = lintFile(file, rules, rootDir);\n allViolations.push(...violations);\n }\n\n if (allViolations.length === 0) {\n console.log(\"No ast-grep lint violations found.\");\n process.exit(0);\n }\n\n console.log(`Found ${allViolations.length} violation(s):\\n`);\n\n for (const v of allViolations) {\n const relPath = path.relative(rootDir, v.file);\n console.log(`${relPath}:${v.line}:${v.column}`);\n console.log(` ${v.rule}: ${v.message}`);\n console.log(` > ${v.code}\\n`);\n }\n\n process.exit(1);\n}\n\nexport const lintCommand = new Command(\"lint\")\n .description(\"Run AST-based linting on TypeScript files\")\n .addHelpText(\n \"after\",\n `\nExamples:\n $ appkit lint`,\n )\n .action(runLint);\n"],"mappings":";;;;;;AAaA,MAAM,QAAgB;CACpB;EACE,IAAI;EACJ,SAAS;EACT,SACE;EACH;CACD;EACE,IAAI;EACJ,SAAS;EACT,SACE;EACF,cAAc;EACf;CACD;EACE,IAAI;EACJ,SAAS;EACT,SACE;EACF,SAAS,SAAS,wBAAwB,KAAK,KAAK;EACrD;CACD;EACE,IAAI;EACJ,SAAS;EACT,SACE;EACH;CACD;EAIE,IAAI;EACJ,SAAS;EACT,SACE;EACF,cAAc;EACf;CACF;AAED,SAAS,WAAW,UAAkB,SAA0B;CAE9D,MAAM,MAAM,KAAK,SAAS,SAAS,SAAS;AAC5C,QACE,2BAA2B,KAAK,IAAI,IAAI,sBAAsB,KAAK,IAAI;;AAI3E,SAAS,YAAY,KAAa,QAAkB,EAAE,EAAY;CAChE,MAAM,UAAU,GAAG,YAAY,KAAK,EAAE,eAAe,MAAM,CAAC;AAE5D,MAAK,MAAM,SAAS,SAAS;EAC3B,MAAM,WAAW,KAAK,KAAK,KAAK,MAAM,KAAK;AAE3C,MAAI,MAAM,aAAa,EAAE;AACvB,OAAI;IAAC;IAAgB;IAAQ;IAAS;IAAO,CAAC,SAAS,MAAM,KAAK,CAChE;AACF,eAAY,UAAU,MAAM;aACnB,MAAM,QAAQ,IAAI,cAAc,KAAK,MAAM,KAAK,CACzD,OAAM,KAAK,SAAS;;AAIxB,QAAO;;AAYT,SAAS,SACP,UACA,OACA,SACa;CACb,MAAM,aAA0B,EAAE;CAClC,MAAM,UAAU,GAAG,aAAa,UAAU,QAAQ;CAClD,MAAM,OAAO,SAAS,SAAS,OAAO,GAAG,KAAK,MAAM,KAAK;CACzD,MAAM,WAAW,WAAW,UAAU,QAAQ;CAG9C,MAAM,OADM,MAAM,MAAM,QAAQ,CACf,MAAM;AAEvB,MAAK,MAAM,QAAQ,OAAO;AAExB,MAAI,YAAY,KAAK,iBAAiB,MAAO;EAE7C,MAAM,UAAU,KAAK,QAAQ,KAAK,QAAQ;AAE1C,OAAK,MAAM,SAAS,SAAS;GAC3B,MAAM,OAAO,MAAM,MAAM;AAEzB,OAAI,KAAK,UAAU,CAAC,KAAK,OAAO,KAAK,CAAE;GAEvC,MAAM,QAAQ,MAAM,OAAO;AAC3B,cAAW,KAAK;IACd,MAAM;IACN,MAAM,MAAM,MAAM,OAAO;IACzB,QAAQ,MAAM,MAAM,SAAS;IAC7B,MAAM,KAAK;IACX,SAAS,KAAK;IACd,MAAM,KAAK,SAAS,KAAK,GAAG,KAAK,MAAM,GAAG,GAAG,CAAC,OAAO;IACtD,CAAC;;;AAIN,QAAO;;;;;AAMT,SAAS,UAAU;CACjB,MAAM,UAAU,QAAQ,KAAK;CAC7B,MAAM,QAAQ,YAAY,QAAQ;AAElC,SAAQ,IAAI,YAAY,MAAM,OAAO,wBAAwB;CAE7D,MAAM,gBAA6B,EAAE;AAErC,MAAK,MAAM,QAAQ,OAAO;EACxB,MAAM,aAAa,SAAS,MAAM,OAAO,QAAQ;AACjD,gBAAc,KAAK,GAAG,WAAW;;AAGnC,KAAI,cAAc,WAAW,GAAG;AAC9B,UAAQ,IAAI,qCAAqC;AACjD,UAAQ,KAAK,EAAE;;AAGjB,SAAQ,IAAI,SAAS,cAAc,OAAO,kBAAkB;AAE5D,MAAK,MAAM,KAAK,eAAe;EAC7B,MAAM,UAAU,KAAK,SAAS,SAAS,EAAE,KAAK;AAC9C,UAAQ,IAAI,GAAG,QAAQ,GAAG,EAAE,KAAK,GAAG,EAAE,SAAS;AAC/C,UAAQ,IAAI,KAAK,EAAE,KAAK,IAAI,EAAE,UAAU;AACxC,UAAQ,IAAI,OAAO,EAAE,KAAK,IAAI;;AAGhC,SAAQ,KAAK,EAAE;;AAGjB,MAAa,cAAc,IAAI,QAAQ,OAAO,CAC3C,YAAY,4CAA4C,CACxD,YACC,SACA;;iBAGD,CACA,OAAO,QAAQ"}
|
package/dist/react/index.d.ts
CHANGED
|
@@ -104,4 +104,7 @@ import { Textarea } from "./ui/textarea.js";
|
|
|
104
104
|
import { Toggle, toggleVariants } from "./ui/toggle.js";
|
|
105
105
|
import { ToggleGroup, ToggleGroupItem } from "./ui/toggle-group.js";
|
|
106
106
|
import "./ui/index.js";
|
|
107
|
-
|
|
107
|
+
import { Variant, VariantProps } from "./ui-variants/variant.js";
|
|
108
|
+
import { Variants, VariantsProps } from "./ui-variants/variants.js";
|
|
109
|
+
import "./ui-variants/index.js";
|
|
110
|
+
export { Accordion, AccordionContent, AccordionItem, AccordionTrigger, AgentChatEvent, AggregatedResourceStatus, Alert, AlertDescription, AlertDialog, AlertDialogAction, AlertDialogCancel, AlertDialogContent, AlertDialogDescription, AlertDialogFooter, AlertDialogHeader, AlertDialogOverlay, AlertDialogPortal, AlertDialogTitle, AlertDialogTrigger, AlertTitle, AnalyticsFormat, AreaChart, AreaChartProps, AreaChartSpecificProps, AspectRatio, Avatar, AvatarFallback, AvatarImage, Badge, BarChart, BarChartProps, BarChartSpecificProps, BaseChart, BaseChartProps, Breadcrumb, BreadcrumbEllipsis, BreadcrumbItem, BreadcrumbLink, BreadcrumbList, BreadcrumbPage, BreadcrumbSeparator, Button, ButtonGroup, ButtonGroupSeparator, ButtonGroupText, CHART_COLOR_VARS, CHART_COLOR_VARS_CATEGORICAL, CHART_COLOR_VARS_DIVERGING, CHART_COLOR_VARS_SEQUENTIAL, Calendar, CalendarDayButton, Card, CardAction, CardContent, CardDescription, CardFooter, CardHeader, CardTitle, Carousel, CarouselApi, CarouselContent, CarouselItem, CarouselNext, CarouselPrevious, CartesianContext, ChartBaseProps, ChartColorPalette, ChartData, ChartInference, ChartType, ChartUITokens, ChartWrapper, ChartWrapperProps, Checkbox, Collapsible, CollapsibleContent, CollapsibleTrigger, ColumnCategory, Command, CommandDialog, CommandEmpty, CommandGroup, CommandInput, CommandItem, CommandList, CommandSeparator, CommandShortcut, ContextMenu, ContextMenuCheckboxItem, ContextMenuContent, ContextMenuGroup, ContextMenuItem, ContextMenuLabel, ContextMenuPortal, ContextMenuRadioGroup, ContextMenuRadioItem, ContextMenuSeparator, ContextMenuShortcut, ContextMenuSub, ContextMenuSubContent, ContextMenuSubTrigger, ContextMenuTrigger, DATE_FIELD_PATTERNS, DataFormat, DataProps, DataTable, Dialog, DialogClose, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogOverlay, DialogPortal, DialogTitle, DialogTrigger, DirectoryEntry, DirectoryList, DirectoryListProps, DonutChart, DonutChartProps, Drawer, DrawerClose, DrawerContent, DrawerDescription, DrawerFooter, DrawerHeader, DrawerOverlay, DrawerPortal, DrawerTitle, DrawerTrigger, DropdownMenu, DropdownMenuCheckboxItem, DropdownMenuContent, DropdownMenuGroup, DropdownMenuItem, DropdownMenuLabel, DropdownMenuPortal, DropdownMenuRadioGroup, DropdownMenuRadioItem, DropdownMenuSeparator, DropdownMenuShortcut, DropdownMenuSub, DropdownMenuSubContent, DropdownMenuSubTrigger, DropdownMenuTrigger, Empty, EmptyContent, EmptyDescription, EmptyHeader, EmptyMedia, EmptyTitle, FALLBACK_COLORS_CATEGORICAL, FALLBACK_COLORS_DIVERGING, FALLBACK_COLORS_SEQUENTIAL, Field, FieldContent, FieldDescription, FieldError, FieldGroup, FieldLabel, FieldLegend, FieldSeparator, FieldSet, FieldTitle, FileBreadcrumb, FileBreadcrumbProps, FileBrowserLabels, FileEntry, FileEntryProps, FilePreview, FilePreviewPanel, FilePreviewPanelProps, Form, FormControl, FormDescription, FormField, FormItem, FormLabel, FormMessage, GenieAttachmentResponse, GenieChat, GenieChatInput, GenieChatMessage, GenieChatMessageList, GenieChatProps, GenieChatStatus, GenieColumnMeta, GenieMessageItem, GenieMessageResponse, GenieQueryVisualization, GenieStatementResponse, GenieStreamEvent, HeatmapChart, HeatmapChartProps, HeatmapChartSpecificProps, HeatmapContext, HoverCard, HoverCardContent, HoverCardTrigger, InferResultByFormat, InferRowType, InferServingChunk, InferServingRequest, InferServingResponse, Input, InputGroup, InputGroupAddon, InputGroupButton, InputGroupInput, InputGroupText, InputGroupTextarea, InputOTP, InputOTPGroup, InputOTPSeparator, InputOTPSlot, Item, ItemActions, ItemContent, ItemDescription, ItemFooter, ItemGroup, ItemHeader, ItemMedia, ItemSeparator, ItemTitle, Kbd, KbdGroup, Label, LineChart, LineChartProps, LineChartSpecificProps, LoadingSkeleton, METADATA_DATE_PATTERNS, Menubar, MenubarCheckboxItem, MenubarContent, MenubarGroup, MenubarItem, MenubarLabel, MenubarMenu, MenubarPortal, MenubarRadioGroup, MenubarRadioItem, MenubarSeparator, MenubarShortcut, MenubarSub, MenubarSubContent, MenubarSubTrigger, MenubarTrigger, NAME_FIELD_PATTERNS, NavigationMenu, NavigationMenuContent, NavigationMenuIndicator, NavigationMenuItem, NavigationMenuLink, NavigationMenuList, NavigationMenuTrigger, NavigationMenuViewport, NewFolderInput, NewFolderInputProps, NormalizedChartData, NormalizedChartDataBase, NormalizedHeatmapData, OptionBuilderContext, Orientation, Pagination, PaginationContent, PaginationEllipsis, PaginationItem, PaginationLink, PaginationNext, PaginationPrevious, PieChart, PieChartProps, PieChartSpecificProps, PluginRegistry, Popover, PopoverAnchor, PopoverContent, PopoverTrigger, PortalContainerContext, PortalContainerProvider, Progress, QueryProps, QueryRegistry, RadarChart, RadarChartProps, RadarChartSpecificProps, RadioGroup, RadioGroupItem, ResizableHandle, ResizablePanel, ResizablePanelGroup, ResourceKindRenderer, ResourceSeverity, ResourceStatus, ResourceStatusFilter, ResourceStatusIndicator, ResourceStatusIndicatorProps, ResourceStatusProvider, ResourceStatusProviderProps, ResourceStatusToasterOptions, ResourceWaitingPlaceholder, ScatterChart, ScatterChartProps, ScatterChartSpecificProps, ScrollArea, ScrollBar, Select, SelectContent, SelectGroup, SelectItem, SelectLabel, SelectScrollDownButton, SelectScrollUpButton, SelectSeparator, SelectTrigger, SelectValue, Separator, ServingAlias, ServingEndpointRegistry, Sheet, SheetClose, SheetContent, SheetDescription, SheetFooter, SheetHeader, SheetTitle, SheetTrigger, Sidebar, SidebarContent, SidebarFooter, SidebarGroup, SidebarGroupAction, SidebarGroupContent, SidebarGroupLabel, SidebarHeader, SidebarInput, SidebarInset, SidebarMenu, SidebarMenuAction, SidebarMenuBadge, SidebarMenuButton, SidebarMenuItem, SidebarMenuSkeleton, SidebarMenuSub, SidebarMenuSubButton, SidebarMenuSubItem, SidebarProvider, SidebarRail, SidebarSeparator, SidebarTrigger, Skeleton, Slider, Spinner, Switch, TERMINAL_STATUSES, Table, TableBody, TableCaption, TableCell, TableFooter, TableHead, TableHeader, TableRow, Tabs, TabsContent, TabsList, TabsTrigger, Textarea, Toaster, Toggle, ToggleGroup, ToggleGroupItem, Tooltip, TooltipContent, TooltipProvider, TooltipTrigger, TransformedGenieData, TypedArrowTable, UnifiedChartProps, UseAgentChatOptions, UseAgentChatResult, UseAnalyticsQueryOptions, UseAnalyticsQueryResult, UseChartDataOptions, UseChartDataResult, UseGenieChatOptions, UseGenieChatReturn, UseServingInvokeOptions, UseServingInvokeResult, UseServingStreamOptions, UseServingStreamResult, Variant, VariantProps, Variants, VariantsProps, WarehouseState, WarehouseStatus, badgeVariants, buildCartesianOption, buildHeatmapOption, buildHorizontalBarOption, buildPieOption, buildRadarOption, buttonGroupVariants, buttonVariants, cn, createChart, createTimeSeriesData, formatFileSize, formatLabel, getCompatibleChartTypes, inferChartType, isArrowTable, isDataProps, isQueryProps, navigationMenuTriggerStyle, normalizeChartData, normalizeHeatmapData, sortTimeSeriesAscending, toChartArray, toChartValue, toggleVariants, transformGenieData, truncateLabel, useAgentChat, useAllThemeColors, useAnalyticsQuery, useChartData, useChartUITokens, useFormField, useGenieChat, useIsMobile, usePluginClientConfig, usePortalContainer, useResolvedPortalContainer, useResourceStatus, useResourceStatusPublisher, useResourceStatusToaster, useServingInvoke, useServingStream, useSidebar, useThemeColors };
|
package/dist/react/index.js
CHANGED
|
@@ -94,5 +94,7 @@ import { Slider } from "./ui/slider.js";
|
|
|
94
94
|
import { Switch } from "./ui/switch.js";
|
|
95
95
|
import { Toggle, toggleVariants } from "./ui/toggle.js";
|
|
96
96
|
import { ToggleGroup, ToggleGroupItem } from "./ui/toggle-group.js";
|
|
97
|
+
import { Variant } from "./ui-variants/variant.js";
|
|
98
|
+
import { Variants } from "./ui-variants/variants.js";
|
|
97
99
|
|
|
98
|
-
export { Accordion, AccordionContent, AccordionItem, AccordionTrigger, Alert, AlertDescription, AlertDialog, AlertDialogAction, AlertDialogCancel, AlertDialogContent, AlertDialogDescription, AlertDialogFooter, AlertDialogHeader, AlertDialogOverlay, AlertDialogPortal, AlertDialogTitle, AlertDialogTrigger, AlertTitle, AreaChart, AspectRatio, Avatar, AvatarFallback, AvatarImage, Badge, BarChart, BaseChart, Breadcrumb, BreadcrumbEllipsis, BreadcrumbItem, BreadcrumbLink, BreadcrumbList, BreadcrumbPage, BreadcrumbSeparator, Button, ButtonGroup, ButtonGroupSeparator, ButtonGroupText, CHART_COLOR_VARS, CHART_COLOR_VARS_CATEGORICAL, CHART_COLOR_VARS_DIVERGING, CHART_COLOR_VARS_SEQUENTIAL, Calendar, CalendarDayButton, Card, CardAction, CardContent, CardDescription, CardFooter, CardHeader, CardTitle, Carousel, CarouselContent, CarouselItem, CarouselNext, CarouselPrevious, ChartWrapper, Checkbox, Collapsible, CollapsibleContent, CollapsibleTrigger, Command, CommandDialog, CommandEmpty, CommandGroup, CommandInput, CommandItem, CommandList, CommandSeparator, CommandShortcut, ContextMenu, ContextMenuCheckboxItem, ContextMenuContent, ContextMenuGroup, ContextMenuItem, ContextMenuLabel, ContextMenuPortal, ContextMenuRadioGroup, ContextMenuRadioItem, ContextMenuSeparator, ContextMenuShortcut, ContextMenuSub, ContextMenuSubContent, ContextMenuSubTrigger, ContextMenuTrigger, DATE_FIELD_PATTERNS, DataTable, Dialog, DialogClose, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogOverlay, DialogPortal, DialogTitle, DialogTrigger, DirectoryList, DonutChart, Drawer, DrawerClose, DrawerContent, DrawerDescription, DrawerFooter, DrawerHeader, DrawerOverlay, DrawerPortal, DrawerTitle, DrawerTrigger, DropdownMenu, DropdownMenuCheckboxItem, DropdownMenuContent, DropdownMenuGroup, DropdownMenuItem, DropdownMenuLabel, DropdownMenuPortal, DropdownMenuRadioGroup, DropdownMenuRadioItem, DropdownMenuSeparator, DropdownMenuShortcut, DropdownMenuSub, DropdownMenuSubContent, DropdownMenuSubTrigger, DropdownMenuTrigger, Empty, EmptyContent, EmptyDescription, EmptyHeader, EmptyMedia, EmptyTitle, FALLBACK_COLORS_CATEGORICAL, FALLBACK_COLORS_DIVERGING, FALLBACK_COLORS_SEQUENTIAL, Field, FieldContent, FieldDescription, FieldError, FieldGroup, FieldLabel, FieldLegend, FieldSeparator, FieldSet, FieldTitle, FileBreadcrumb, FileEntry, FilePreviewPanel, Form, FormControl, FormDescription, FormField, FormItem, FormLabel, FormMessage, GenieChat, GenieChatInput, GenieChatMessage, GenieChatMessageList, GenieQueryVisualization, HeatmapChart, HoverCard, HoverCardContent, HoverCardTrigger, Input, InputGroup, InputGroupAddon, InputGroupButton, InputGroupInput, InputGroupText, InputGroupTextarea, InputOTP, InputOTPGroup, InputOTPSeparator, InputOTPSlot, Item, ItemActions, ItemContent, ItemDescription, ItemFooter, ItemGroup, ItemHeader, ItemMedia, ItemSeparator, ItemTitle, Kbd, KbdGroup, Label, LineChart, LoadingSkeleton, METADATA_DATE_PATTERNS, Menubar, MenubarCheckboxItem, MenubarContent, MenubarGroup, MenubarItem, MenubarLabel, MenubarMenu, MenubarPortal, MenubarRadioGroup, MenubarRadioItem, MenubarSeparator, MenubarShortcut, MenubarSub, MenubarSubContent, MenubarSubTrigger, MenubarTrigger, NAME_FIELD_PATTERNS, NavigationMenu, NavigationMenuContent, NavigationMenuIndicator, NavigationMenuItem, NavigationMenuLink, NavigationMenuList, NavigationMenuTrigger, NavigationMenuViewport, NewFolderInput, Pagination, PaginationContent, PaginationEllipsis, PaginationItem, PaginationLink, PaginationNext, PaginationPrevious, PieChart, Popover, PopoverAnchor, PopoverContent, PopoverTrigger, PortalContainerContext, PortalContainerProvider, Progress, RadarChart, RadioGroup, RadioGroupItem, ResizableHandle, ResizablePanel, ResizablePanelGroup, ResourceStatusIndicator, ResourceStatusProvider, ResourceWaitingPlaceholder, ScatterChart, ScrollArea, ScrollBar, Select, SelectContent, SelectGroup, SelectItem, SelectLabel, SelectScrollDownButton, SelectScrollUpButton, SelectSeparator, SelectTrigger, SelectValue, Separator, Sheet, SheetClose, SheetContent, SheetDescription, SheetFooter, SheetHeader, SheetTitle, SheetTrigger, Sidebar, SidebarContent, SidebarFooter, SidebarGroup, SidebarGroupAction, SidebarGroupContent, SidebarGroupLabel, SidebarHeader, SidebarInput, SidebarInset, SidebarMenu, SidebarMenuAction, SidebarMenuBadge, SidebarMenuButton, SidebarMenuItem, SidebarMenuSkeleton, SidebarMenuSub, SidebarMenuSubButton, SidebarMenuSubItem, SidebarProvider, SidebarRail, SidebarSeparator, SidebarTrigger, Skeleton, Slider, Spinner, Switch, Table, TableBody, TableCaption, TableCell, TableFooter, TableHead, TableHeader, TableRow, Tabs, TabsContent, TabsList, TabsTrigger, Textarea, Toaster, Toggle, ToggleGroup, ToggleGroupItem, Tooltip, TooltipContent, TooltipProvider, TooltipTrigger, badgeVariants, buildCartesianOption, buildHeatmapOption, buildHorizontalBarOption, buildPieOption, buildRadarOption, buttonGroupVariants, buttonVariants, cn, createChart, createTimeSeriesData, formatFileSize, formatLabel, getCompatibleChartTypes, inferChartType, isArrowTable, isDataProps, isQueryProps, navigationMenuTriggerStyle, normalizeChartData, normalizeHeatmapData, sortTimeSeriesAscending, toChartArray, toChartValue, toggleVariants, transformGenieData, truncateLabel, useAgentChat, useAllThemeColors, useAnalyticsQuery, useChartData, useChartUITokens, useFormField, useGenieChat, useIsMobile, usePluginClientConfig, usePortalContainer, useResolvedPortalContainer, useResourceStatus, useResourceStatusPublisher, useResourceStatusToaster, useServingInvoke, useServingStream, useSidebar, useThemeColors };
|
|
100
|
+
export { Accordion, AccordionContent, AccordionItem, AccordionTrigger, Alert, AlertDescription, AlertDialog, AlertDialogAction, AlertDialogCancel, AlertDialogContent, AlertDialogDescription, AlertDialogFooter, AlertDialogHeader, AlertDialogOverlay, AlertDialogPortal, AlertDialogTitle, AlertDialogTrigger, AlertTitle, AreaChart, AspectRatio, Avatar, AvatarFallback, AvatarImage, Badge, BarChart, BaseChart, Breadcrumb, BreadcrumbEllipsis, BreadcrumbItem, BreadcrumbLink, BreadcrumbList, BreadcrumbPage, BreadcrumbSeparator, Button, ButtonGroup, ButtonGroupSeparator, ButtonGroupText, CHART_COLOR_VARS, CHART_COLOR_VARS_CATEGORICAL, CHART_COLOR_VARS_DIVERGING, CHART_COLOR_VARS_SEQUENTIAL, Calendar, CalendarDayButton, Card, CardAction, CardContent, CardDescription, CardFooter, CardHeader, CardTitle, Carousel, CarouselContent, CarouselItem, CarouselNext, CarouselPrevious, ChartWrapper, Checkbox, Collapsible, CollapsibleContent, CollapsibleTrigger, Command, CommandDialog, CommandEmpty, CommandGroup, CommandInput, CommandItem, CommandList, CommandSeparator, CommandShortcut, ContextMenu, ContextMenuCheckboxItem, ContextMenuContent, ContextMenuGroup, ContextMenuItem, ContextMenuLabel, ContextMenuPortal, ContextMenuRadioGroup, ContextMenuRadioItem, ContextMenuSeparator, ContextMenuShortcut, ContextMenuSub, ContextMenuSubContent, ContextMenuSubTrigger, ContextMenuTrigger, DATE_FIELD_PATTERNS, DataTable, Dialog, DialogClose, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogOverlay, DialogPortal, DialogTitle, DialogTrigger, DirectoryList, DonutChart, Drawer, DrawerClose, DrawerContent, DrawerDescription, DrawerFooter, DrawerHeader, DrawerOverlay, DrawerPortal, DrawerTitle, DrawerTrigger, DropdownMenu, DropdownMenuCheckboxItem, DropdownMenuContent, DropdownMenuGroup, DropdownMenuItem, DropdownMenuLabel, DropdownMenuPortal, DropdownMenuRadioGroup, DropdownMenuRadioItem, DropdownMenuSeparator, DropdownMenuShortcut, DropdownMenuSub, DropdownMenuSubContent, DropdownMenuSubTrigger, DropdownMenuTrigger, Empty, EmptyContent, EmptyDescription, EmptyHeader, EmptyMedia, EmptyTitle, FALLBACK_COLORS_CATEGORICAL, FALLBACK_COLORS_DIVERGING, FALLBACK_COLORS_SEQUENTIAL, Field, FieldContent, FieldDescription, FieldError, FieldGroup, FieldLabel, FieldLegend, FieldSeparator, FieldSet, FieldTitle, FileBreadcrumb, FileEntry, FilePreviewPanel, Form, FormControl, FormDescription, FormField, FormItem, FormLabel, FormMessage, GenieChat, GenieChatInput, GenieChatMessage, GenieChatMessageList, GenieQueryVisualization, HeatmapChart, HoverCard, HoverCardContent, HoverCardTrigger, Input, InputGroup, InputGroupAddon, InputGroupButton, InputGroupInput, InputGroupText, InputGroupTextarea, InputOTP, InputOTPGroup, InputOTPSeparator, InputOTPSlot, Item, ItemActions, ItemContent, ItemDescription, ItemFooter, ItemGroup, ItemHeader, ItemMedia, ItemSeparator, ItemTitle, Kbd, KbdGroup, Label, LineChart, LoadingSkeleton, METADATA_DATE_PATTERNS, Menubar, MenubarCheckboxItem, MenubarContent, MenubarGroup, MenubarItem, MenubarLabel, MenubarMenu, MenubarPortal, MenubarRadioGroup, MenubarRadioItem, MenubarSeparator, MenubarShortcut, MenubarSub, MenubarSubContent, MenubarSubTrigger, MenubarTrigger, NAME_FIELD_PATTERNS, NavigationMenu, NavigationMenuContent, NavigationMenuIndicator, NavigationMenuItem, NavigationMenuLink, NavigationMenuList, NavigationMenuTrigger, NavigationMenuViewport, NewFolderInput, Pagination, PaginationContent, PaginationEllipsis, PaginationItem, PaginationLink, PaginationNext, PaginationPrevious, PieChart, Popover, PopoverAnchor, PopoverContent, PopoverTrigger, PortalContainerContext, PortalContainerProvider, Progress, RadarChart, RadioGroup, RadioGroupItem, ResizableHandle, ResizablePanel, ResizablePanelGroup, ResourceStatusIndicator, ResourceStatusProvider, ResourceWaitingPlaceholder, ScatterChart, ScrollArea, ScrollBar, Select, SelectContent, SelectGroup, SelectItem, SelectLabel, SelectScrollDownButton, SelectScrollUpButton, SelectSeparator, SelectTrigger, SelectValue, Separator, Sheet, SheetClose, SheetContent, SheetDescription, SheetFooter, SheetHeader, SheetTitle, SheetTrigger, Sidebar, SidebarContent, SidebarFooter, SidebarGroup, SidebarGroupAction, SidebarGroupContent, SidebarGroupLabel, SidebarHeader, SidebarInput, SidebarInset, SidebarMenu, SidebarMenuAction, SidebarMenuBadge, SidebarMenuButton, SidebarMenuItem, SidebarMenuSkeleton, SidebarMenuSub, SidebarMenuSubButton, SidebarMenuSubItem, SidebarProvider, SidebarRail, SidebarSeparator, SidebarTrigger, Skeleton, Slider, Spinner, Switch, Table, TableBody, TableCaption, TableCell, TableFooter, TableHead, TableHeader, TableRow, Tabs, TabsContent, TabsList, TabsTrigger, Textarea, Toaster, Toggle, ToggleGroup, ToggleGroupItem, Tooltip, TooltipContent, TooltipProvider, TooltipTrigger, Variant, Variants, badgeVariants, buildCartesianOption, buildHeatmapOption, buildHorizontalBarOption, buildPieOption, buildRadarOption, buttonGroupVariants, buttonVariants, cn, createChart, createTimeSeriesData, formatFileSize, formatLabel, getCompatibleChartTypes, inferChartType, isArrowTable, isDataProps, isQueryProps, navigationMenuTriggerStyle, normalizeChartData, normalizeHeatmapData, sortTimeSeriesAscending, toChartArray, toChartValue, toggleVariants, transformGenieData, truncateLabel, useAgentChat, useAllThemeColors, useAnalyticsQuery, useChartData, useChartUITokens, useFormField, useGenieChat, useIsMobile, usePluginClientConfig, usePortalContainer, useResolvedPortalContainer, useResourceStatus, useResourceStatusPublisher, useResourceStatusToaster, useServingInvoke, useServingStream, useSidebar, useThemeColors };
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import * as React$1 from "react";
|
|
2
|
+
import * as react_jsx_runtime0 from "react/jsx-runtime";
|
|
3
|
+
|
|
4
|
+
//#region src/react/ui-variants/variant.d.ts
|
|
5
|
+
/** Props for a single {@link Variant} inside a {@link Variants} block. */
|
|
6
|
+
interface VariantProps {
|
|
7
|
+
/** Human-readable label shown in the switcher and recorded on confirm. */
|
|
8
|
+
label?: string;
|
|
9
|
+
children: React$1.ReactNode;
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* One candidate inside a {@link Variants} block. Purely a declarative marker:
|
|
13
|
+
* `Variants` reads its `label` and renders its `children` for the active
|
|
14
|
+
* index. It is not meant to be rendered on its own.
|
|
15
|
+
*/
|
|
16
|
+
declare function Variant({
|
|
17
|
+
children
|
|
18
|
+
}: VariantProps): react_jsx_runtime0.JSX.Element;
|
|
19
|
+
//#endregion
|
|
20
|
+
export { Variant, VariantProps };
|
|
21
|
+
//# sourceMappingURL=variant.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"variant.d.ts","names":[],"sources":["../../../src/react/ui-variants/variant.tsx"],"mappings":";;;;;UAGiB,YAAA;;EAEf,KAAA;EACA,QAAA,EAAU,OAAA,CAAM,SAAA;AAAA;;;;;;iBAQF,OAAA,CAAA;EAAU;AAAA,GAAY,YAAA,GAAY,kBAAA,CAAA,GAAA,CAAA,OAAA"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { Fragment, jsx } from "react/jsx-runtime";
|
|
2
|
+
|
|
3
|
+
//#region src/react/ui-variants/variant.tsx
|
|
4
|
+
/**
|
|
5
|
+
* One candidate inside a {@link Variants} block. Purely a declarative marker:
|
|
6
|
+
* `Variants` reads its `label` and renders its `children` for the active
|
|
7
|
+
* index. It is not meant to be rendered on its own.
|
|
8
|
+
*/
|
|
9
|
+
function Variant({ children }) {
|
|
10
|
+
return /* @__PURE__ */ jsx(Fragment, { children });
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
//#endregion
|
|
14
|
+
export { Variant };
|
|
15
|
+
//# sourceMappingURL=variant.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"variant.js","names":[],"sources":["../../../src/react/ui-variants/variant.tsx"],"sourcesContent":["import type * as React from \"react\";\n\n/** Props for a single {@link Variant} inside a {@link Variants} block. */\nexport interface VariantProps {\n /** Human-readable label shown in the switcher and recorded on confirm. */\n label?: string;\n children: React.ReactNode;\n}\n\n/**\n * One candidate inside a {@link Variants} block. Purely a declarative marker:\n * `Variants` reads its `label` and renders its `children` for the active\n * index. It is not meant to be rendered on its own.\n */\nexport function Variant({ children }: VariantProps) {\n return <>{children}</>;\n}\n"],"mappings":";;;;;;;;AAcA,SAAgB,QAAQ,EAAE,YAA0B;AAClD,QAAO,gCAAG,WAAY"}
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
import { ReactNode } from "react";
|
|
2
|
+
import * as react_jsx_runtime0 from "react/jsx-runtime";
|
|
3
|
+
|
|
4
|
+
//#region src/react/ui-variants/variants.d.ts
|
|
5
|
+
/** Props for {@link Variants}. */
|
|
6
|
+
interface VariantsProps {
|
|
7
|
+
/**
|
|
8
|
+
* Stable, unique identifier for this block. The variant-picking agent matches
|
|
9
|
+
* on it to finalize the chosen variant into source, so it must be unique per
|
|
10
|
+
* file. (Named `blockId`, not `id`, because it is a semantic key — not a DOM
|
|
11
|
+
* element id.)
|
|
12
|
+
*/
|
|
13
|
+
blockId: string;
|
|
14
|
+
/** `<Variant>` children — one candidate UI each. */
|
|
15
|
+
children: ReactNode;
|
|
16
|
+
/**
|
|
17
|
+
* How the wrapper flows in the layout. Defaults to `"block"` (full width,
|
|
18
|
+
* variants stack vertically) — the right choice for page sections, heroes,
|
|
19
|
+
* and other block-level regions, which is the common case. Use `"inline"`
|
|
20
|
+
* when wrapping a small inline element such as a single button, so the
|
|
21
|
+
* wrapper hugs its content instead of spanning the row.
|
|
22
|
+
*/
|
|
23
|
+
layout?: "block" | "inline";
|
|
24
|
+
/** Class name applied to the block wrapper (merged after `layout`). */
|
|
25
|
+
className?: string;
|
|
26
|
+
/**
|
|
27
|
+
* Any CSS color for the switcher chrome (dot, ring, control cluster, count
|
|
28
|
+
* pill, confirm tick). Every accent element derives from this one value.
|
|
29
|
+
* Defaults to {@link DEFAULT_ACCENT}. The error state stays red regardless.
|
|
30
|
+
*
|
|
31
|
+
* @example accent="var(--primary)" // match the app theme
|
|
32
|
+
* @example accent="#f43f5e" // rose
|
|
33
|
+
*/
|
|
34
|
+
accent?: string;
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Dev-time UI picker: renders several `<Variant>` candidates one at a time.
|
|
38
|
+
*
|
|
39
|
+
* At rest the block shows a small, slowly-pulsing corner dot so it's clear
|
|
40
|
+
* it's "in variant state" without hovering — the dot pulses while a choice is
|
|
41
|
+
* still pending and goes calm once recorded. On hover (or focus) an accent
|
|
42
|
+
* ring outlines the block and the dot gives way to a compact control cluster
|
|
43
|
+
* (‹ index/total › ✓) that scales out of the corner. Confirming POSTs the
|
|
44
|
+
* choice to the `uiVariants()` recorder plugin; a coding agent then finalizes
|
|
45
|
+
* the chosen variant into source, removing this wrapper.
|
|
46
|
+
*
|
|
47
|
+
* All switcher chrome uses the `accent` color (default {@link DEFAULT_ACCENT},
|
|
48
|
+
* a violet distinct from most apps' `primary`) so it doesn't blend into the
|
|
49
|
+
* content it wraps.
|
|
50
|
+
*
|
|
51
|
+
* Degrades gracefully. In a production build the picker chrome is dropped
|
|
52
|
+
* entirely and only the first variant renders as plain content — a safety net
|
|
53
|
+
* for a block that shipped without being finalized. In dev, if the recorder
|
|
54
|
+
* endpoint is absent (feature off) the switcher still works as a viewer and
|
|
55
|
+
* Confirm reports that recording is unavailable.
|
|
56
|
+
*
|
|
57
|
+
* @example Page section (default layout — full-width, stacks vertically)
|
|
58
|
+
* ```tsx
|
|
59
|
+
* <Variants blockId="hero">
|
|
60
|
+
* <Variant label="Split"><section>…</section></Variant>
|
|
61
|
+
* <Variant label="Centered"><section>…</section></Variant>
|
|
62
|
+
* </Variants>
|
|
63
|
+
* ```
|
|
64
|
+
*
|
|
65
|
+
* @example Small inline element (hug the content)
|
|
66
|
+
* ```tsx
|
|
67
|
+
* <Variants blockId="hero-cta" layout="inline">
|
|
68
|
+
* <Variant label="Ghost"><Button variant="ghost">Get started</Button></Variant>
|
|
69
|
+
* <Variant label="Solid"><Button>Get started</Button></Variant>
|
|
70
|
+
* </Variants>
|
|
71
|
+
* ```
|
|
72
|
+
*
|
|
73
|
+
* @example Custom accent
|
|
74
|
+
* ```tsx
|
|
75
|
+
* <Variants blockId="hero" accent="#f43f5e">…</Variants>
|
|
76
|
+
* ```
|
|
77
|
+
*/
|
|
78
|
+
declare function Variants({
|
|
79
|
+
blockId,
|
|
80
|
+
children,
|
|
81
|
+
layout,
|
|
82
|
+
className,
|
|
83
|
+
accent
|
|
84
|
+
}: VariantsProps): react_jsx_runtime0.JSX.Element | null;
|
|
85
|
+
//#endregion
|
|
86
|
+
export { Variants, VariantsProps };
|
|
87
|
+
//# sourceMappingURL=variants.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"variants.d.ts","names":[],"sources":["../../../src/react/ui-variants/variants.tsx"],"mappings":";;;;;UAoCiB,aAAA;;AAAjB;;;;;EAOE,OAAA;EAEU;EAAV,QAAA,EAAU,SAAA;EAUV;;;;AA0DF;;;EA5DE,MAAA;EA8DA;EA5DA,SAAA;EA8DA;;;;;;;;EArDA,MAAA;AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBAiDc,QAAA,CAAA;EACd,OAAA;EACA,QAAA;EACA,MAAA;EACA,SAAA;EACA;AAAA,GACC,aAAA,GAAa,kBAAA,CAAA,GAAA,CAAA,OAAA"}
|
|
@@ -0,0 +1,199 @@
|
|
|
1
|
+
import { cn } from "../lib/utils.js";
|
|
2
|
+
import { Variant } from "./variant.js";
|
|
3
|
+
import { Children, isValidElement, useMemo, useState } from "react";
|
|
4
|
+
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
5
|
+
import { Check, CheckCheck, ChevronLeft, ChevronRight, Loader2 } from "lucide-react";
|
|
6
|
+
|
|
7
|
+
//#region src/react/ui-variants/variants.tsx
|
|
8
|
+
/** Endpoint the recorder plugin (`uiVariants()`) mounts in development. */
|
|
9
|
+
const CONFIRM_ENDPOINT = "/api/ui-variants/confirm";
|
|
10
|
+
/** Abort the confirm request after this long so the button can't hang. */
|
|
11
|
+
const CONFIRM_TIMEOUT_MS = 5e3;
|
|
12
|
+
/**
|
|
13
|
+
* Default switcher accent — a violet chosen to stand apart from most apps'
|
|
14
|
+
* `primary`, so the dev-only picker chrome doesn't blend into the content it
|
|
15
|
+
* wraps. Override per-block via the `accent` prop.
|
|
16
|
+
*/
|
|
17
|
+
const DEFAULT_ACCENT = "#8b5cf6";
|
|
18
|
+
function isVariantElement(node) {
|
|
19
|
+
return isValidElement(node) && node.type === Variant;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Dev-time UI picker: renders several `<Variant>` candidates one at a time.
|
|
23
|
+
*
|
|
24
|
+
* At rest the block shows a small, slowly-pulsing corner dot so it's clear
|
|
25
|
+
* it's "in variant state" without hovering — the dot pulses while a choice is
|
|
26
|
+
* still pending and goes calm once recorded. On hover (or focus) an accent
|
|
27
|
+
* ring outlines the block and the dot gives way to a compact control cluster
|
|
28
|
+
* (‹ index/total › ✓) that scales out of the corner. Confirming POSTs the
|
|
29
|
+
* choice to the `uiVariants()` recorder plugin; a coding agent then finalizes
|
|
30
|
+
* the chosen variant into source, removing this wrapper.
|
|
31
|
+
*
|
|
32
|
+
* All switcher chrome uses the `accent` color (default {@link DEFAULT_ACCENT},
|
|
33
|
+
* a violet distinct from most apps' `primary`) so it doesn't blend into the
|
|
34
|
+
* content it wraps.
|
|
35
|
+
*
|
|
36
|
+
* Degrades gracefully. In a production build the picker chrome is dropped
|
|
37
|
+
* entirely and only the first variant renders as plain content — a safety net
|
|
38
|
+
* for a block that shipped without being finalized. In dev, if the recorder
|
|
39
|
+
* endpoint is absent (feature off) the switcher still works as a viewer and
|
|
40
|
+
* Confirm reports that recording is unavailable.
|
|
41
|
+
*
|
|
42
|
+
* @example Page section (default layout — full-width, stacks vertically)
|
|
43
|
+
* ```tsx
|
|
44
|
+
* <Variants blockId="hero">
|
|
45
|
+
* <Variant label="Split"><section>…</section></Variant>
|
|
46
|
+
* <Variant label="Centered"><section>…</section></Variant>
|
|
47
|
+
* </Variants>
|
|
48
|
+
* ```
|
|
49
|
+
*
|
|
50
|
+
* @example Small inline element (hug the content)
|
|
51
|
+
* ```tsx
|
|
52
|
+
* <Variants blockId="hero-cta" layout="inline">
|
|
53
|
+
* <Variant label="Ghost"><Button variant="ghost">Get started</Button></Variant>
|
|
54
|
+
* <Variant label="Solid"><Button>Get started</Button></Variant>
|
|
55
|
+
* </Variants>
|
|
56
|
+
* ```
|
|
57
|
+
*
|
|
58
|
+
* @example Custom accent
|
|
59
|
+
* ```tsx
|
|
60
|
+
* <Variants blockId="hero" accent="#f43f5e">…</Variants>
|
|
61
|
+
* ```
|
|
62
|
+
*/
|
|
63
|
+
function Variants({ blockId, children, layout = "block", className, accent = DEFAULT_ACCENT }) {
|
|
64
|
+
const variants = useMemo(() => Children.toArray(children).filter(isVariantElement), [children]);
|
|
65
|
+
const [active, setActive] = useState(0);
|
|
66
|
+
const [confirmState, setConfirmState] = useState("idle");
|
|
67
|
+
if (variants.length === 0) return null;
|
|
68
|
+
if (!import.meta.env.DEV) return /* @__PURE__ */ jsx(Fragment, { children: variants[0] });
|
|
69
|
+
const clampedActive = Math.min(active, variants.length - 1);
|
|
70
|
+
const current = variants[clampedActive];
|
|
71
|
+
const label = current.props.label ?? `Variant ${clampedActive + 1}`;
|
|
72
|
+
const atStart = clampedActive === 0;
|
|
73
|
+
const atEnd = clampedActive === variants.length - 1;
|
|
74
|
+
const go = (delta) => {
|
|
75
|
+
setActive((i) => Math.max(0, Math.min(variants.length - 1, i + delta)));
|
|
76
|
+
setConfirmState("idle");
|
|
77
|
+
};
|
|
78
|
+
const confirm = async () => {
|
|
79
|
+
if (confirmState === "saving") return;
|
|
80
|
+
setConfirmState("saving");
|
|
81
|
+
const controller = new AbortController();
|
|
82
|
+
const timeout = setTimeout(() => controller.abort(), CONFIRM_TIMEOUT_MS);
|
|
83
|
+
try {
|
|
84
|
+
const res = await fetch(CONFIRM_ENDPOINT, {
|
|
85
|
+
method: "POST",
|
|
86
|
+
headers: { "Content-Type": "application/json" },
|
|
87
|
+
body: JSON.stringify({
|
|
88
|
+
blockId,
|
|
89
|
+
chosenIndex: clampedActive,
|
|
90
|
+
label
|
|
91
|
+
}),
|
|
92
|
+
signal: controller.signal
|
|
93
|
+
});
|
|
94
|
+
if (res.status === 404 || res.status === 403) {
|
|
95
|
+
setConfirmState("unavailable");
|
|
96
|
+
return;
|
|
97
|
+
}
|
|
98
|
+
setConfirmState(res.ok ? "recorded" : "error");
|
|
99
|
+
} catch {
|
|
100
|
+
setConfirmState("error");
|
|
101
|
+
} finally {
|
|
102
|
+
clearTimeout(timeout);
|
|
103
|
+
}
|
|
104
|
+
};
|
|
105
|
+
return /* @__PURE__ */ jsxs("div", {
|
|
106
|
+
"data-slot": "variants",
|
|
107
|
+
style: { "--variants-accent": accent },
|
|
108
|
+
className: cn("group relative rounded-md ring-[color:var(--variants-accent)] transition-[box-shadow] duration-200", layout === "inline" ? "inline-block" : "block w-full", "hover:ring-1 focus-within:ring-1", className),
|
|
109
|
+
children: [
|
|
110
|
+
current,
|
|
111
|
+
/* @__PURE__ */ jsx(StateDot, {
|
|
112
|
+
state: confirmState,
|
|
113
|
+
className: "group-hover:pointer-events-none group-hover:opacity-0 group-focus-within:pointer-events-none group-focus-within:opacity-0"
|
|
114
|
+
}),
|
|
115
|
+
/* @__PURE__ */ jsxs("div", {
|
|
116
|
+
"data-slot": "variants-switcher",
|
|
117
|
+
className: cn("absolute -top-3 right-0 z-20 flex items-center gap-0.5 rounded-full border bg-background/95 px-1 py-0.5 shadow-md backdrop-blur", "border-[color-mix(in_srgb,var(--variants-accent)_40%,transparent)]", "pointer-events-none origin-top-right scale-90 opacity-0 transition-all duration-150", "group-hover:pointer-events-auto group-hover:scale-100 group-hover:opacity-100", "group-focus-within:pointer-events-auto group-focus-within:scale-100 group-focus-within:opacity-100"),
|
|
118
|
+
children: [
|
|
119
|
+
/* @__PURE__ */ jsx(RoundButton, {
|
|
120
|
+
"aria-label": "Previous variant",
|
|
121
|
+
disabled: atStart,
|
|
122
|
+
onClick: () => go(-1),
|
|
123
|
+
children: /* @__PURE__ */ jsx(ChevronLeft, { className: "size-3.5" })
|
|
124
|
+
}),
|
|
125
|
+
/* @__PURE__ */ jsxs("span", {
|
|
126
|
+
className: "select-none rounded-full bg-[color-mix(in_srgb,var(--variants-accent)_15%,transparent)] px-1 text-[10px] font-semibold text-[color:var(--variants-accent)] tabular-nums",
|
|
127
|
+
children: [
|
|
128
|
+
clampedActive + 1,
|
|
129
|
+
"/",
|
|
130
|
+
variants.length
|
|
131
|
+
]
|
|
132
|
+
}),
|
|
133
|
+
/* @__PURE__ */ jsx(RoundButton, {
|
|
134
|
+
"aria-label": "Next variant",
|
|
135
|
+
disabled: atEnd,
|
|
136
|
+
onClick: () => go(1),
|
|
137
|
+
children: /* @__PURE__ */ jsx(ChevronRight, { className: "size-3.5" })
|
|
138
|
+
}),
|
|
139
|
+
/* @__PURE__ */ jsx(ConfirmButton, {
|
|
140
|
+
state: confirmState,
|
|
141
|
+
label,
|
|
142
|
+
onClick: confirm
|
|
143
|
+
})
|
|
144
|
+
]
|
|
145
|
+
})
|
|
146
|
+
]
|
|
147
|
+
});
|
|
148
|
+
}
|
|
149
|
+
function dotColorFor(state) {
|
|
150
|
+
switch (state) {
|
|
151
|
+
case "error": return "bg-destructive";
|
|
152
|
+
case "unavailable": return "bg-muted-foreground/40";
|
|
153
|
+
default: return "bg-[color:var(--variants-accent)]";
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
/**
|
|
157
|
+
* Resting corner indicator: pulses while a choice is pending, calm once
|
|
158
|
+
* recorded — so a block's picked/unpicked state reads at a glance without
|
|
159
|
+
* hovering.
|
|
160
|
+
*/
|
|
161
|
+
function StateDot({ state, className }) {
|
|
162
|
+
const pulsing = state === "idle" || state === "saving";
|
|
163
|
+
const color = dotColorFor(state);
|
|
164
|
+
return /* @__PURE__ */ jsxs("span", {
|
|
165
|
+
"aria-hidden": true,
|
|
166
|
+
"data-slot": "variants-dot",
|
|
167
|
+
className: cn("absolute -top-1 -right-1 z-10 flex size-3 items-center justify-center transition-opacity duration-150", className),
|
|
168
|
+
children: [pulsing && /* @__PURE__ */ jsx("span", { className: cn("absolute inline-flex size-full animate-ping rounded-full opacity-50 [animation-duration:2.5s]", color) }), /* @__PURE__ */ jsx("span", { className: cn("relative inline-flex size-2.5 rounded-full ring-2 ring-background", color) })]
|
|
169
|
+
});
|
|
170
|
+
}
|
|
171
|
+
function RoundButton({ children, disabled, className, ...props }) {
|
|
172
|
+
return /* @__PURE__ */ jsx("button", {
|
|
173
|
+
type: "button",
|
|
174
|
+
disabled,
|
|
175
|
+
className: cn("inline-flex size-6 items-center justify-center rounded-full text-muted-foreground transition-colors", "hover:bg-accent hover:text-accent-foreground", "disabled:pointer-events-none disabled:opacity-30", className),
|
|
176
|
+
...props,
|
|
177
|
+
children
|
|
178
|
+
});
|
|
179
|
+
}
|
|
180
|
+
/**
|
|
181
|
+
* Round tick that confirms the active variant. State is conveyed by icon +
|
|
182
|
+
* color only (no text). The chosen `label` rides along in the title/aria for
|
|
183
|
+
* accessibility and hover context.
|
|
184
|
+
*/
|
|
185
|
+
function ConfirmButton({ state, label, onClick }) {
|
|
186
|
+
const title = state === "recorded" ? `Recorded "${label}" — ask the agent to finalize` : state === "unavailable" ? "Recorder unavailable" : state === "error" ? "Failed — click to retry" : `Confirm "${label}"`;
|
|
187
|
+
return /* @__PURE__ */ jsx(RoundButton, {
|
|
188
|
+
"aria-label": title,
|
|
189
|
+
title,
|
|
190
|
+
disabled: state === "saving" || state === "unavailable",
|
|
191
|
+
onClick,
|
|
192
|
+
className: cn(state === "recorded" && "text-[color:var(--variants-accent)] hover:bg-[color-mix(in_srgb,var(--variants-accent)_12%,transparent)] hover:text-[color:var(--variants-accent)]", state === "error" && "text-destructive hover:bg-destructive/10 hover:text-destructive", (state === "idle" || state === "saving") && "hover:bg-[color-mix(in_srgb,var(--variants-accent)_12%,transparent)] hover:text-[color:var(--variants-accent)]"),
|
|
193
|
+
children: state === "saving" ? /* @__PURE__ */ jsx(Loader2, { className: "size-3.5 animate-spin" }) : state === "recorded" ? /* @__PURE__ */ jsx(CheckCheck, { className: "size-3.5" }) : /* @__PURE__ */ jsx(Check, { className: "size-3.5" })
|
|
194
|
+
});
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
//#endregion
|
|
198
|
+
export { Variants };
|
|
199
|
+
//# sourceMappingURL=variants.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"variants.js","names":[],"sources":["../../../src/react/ui-variants/variants.tsx"],"sourcesContent":["import {\n Check,\n CheckCheck,\n ChevronLeft,\n ChevronRight,\n Loader2,\n} from \"lucide-react\";\nimport {\n Children,\n type ComponentProps,\n type CSSProperties,\n isValidElement,\n type ReactElement,\n type ReactNode,\n useMemo,\n useState,\n} from \"react\";\nimport { cn } from \"../lib/utils\";\nimport { Variant, type VariantProps } from \"./variant\";\n\n/** Endpoint the recorder plugin (`uiVariants()`) mounts in development. */\nconst CONFIRM_ENDPOINT = \"/api/ui-variants/confirm\";\n\n/** Abort the confirm request after this long so the button can't hang. */\nconst CONFIRM_TIMEOUT_MS = 5000;\n\n/**\n * Default switcher accent — a violet chosen to stand apart from most apps'\n * `primary`, so the dev-only picker chrome doesn't blend into the content it\n * wraps. Override per-block via the `accent` prop.\n */\nconst DEFAULT_ACCENT = \"#8b5cf6\";\n\ntype ConfirmState = \"idle\" | \"saving\" | \"recorded\" | \"unavailable\" | \"error\";\n\n/** Props for {@link Variants}. */\nexport interface VariantsProps {\n /**\n * Stable, unique identifier for this block. The variant-picking agent matches\n * on it to finalize the chosen variant into source, so it must be unique per\n * file. (Named `blockId`, not `id`, because it is a semantic key — not a DOM\n * element id.)\n */\n blockId: string;\n /** `<Variant>` children — one candidate UI each. */\n children: ReactNode;\n /**\n * How the wrapper flows in the layout. Defaults to `\"block\"` (full width,\n * variants stack vertically) — the right choice for page sections, heroes,\n * and other block-level regions, which is the common case. Use `\"inline\"`\n * when wrapping a small inline element such as a single button, so the\n * wrapper hugs its content instead of spanning the row.\n */\n layout?: \"block\" | \"inline\";\n /** Class name applied to the block wrapper (merged after `layout`). */\n className?: string;\n /**\n * Any CSS color for the switcher chrome (dot, ring, control cluster, count\n * pill, confirm tick). Every accent element derives from this one value.\n * Defaults to {@link DEFAULT_ACCENT}. The error state stays red regardless.\n *\n * @example accent=\"var(--primary)\" // match the app theme\n * @example accent=\"#f43f5e\" // rose\n */\n accent?: string;\n}\n\nfunction isVariantElement(node: ReactNode): node is ReactElement<VariantProps> {\n return isValidElement(node) && node.type === Variant;\n}\n\n/**\n * Dev-time UI picker: renders several `<Variant>` candidates one at a time.\n *\n * At rest the block shows a small, slowly-pulsing corner dot so it's clear\n * it's \"in variant state\" without hovering — the dot pulses while a choice is\n * still pending and goes calm once recorded. On hover (or focus) an accent\n * ring outlines the block and the dot gives way to a compact control cluster\n * (‹ index/total › ✓) that scales out of the corner. Confirming POSTs the\n * choice to the `uiVariants()` recorder plugin; a coding agent then finalizes\n * the chosen variant into source, removing this wrapper.\n *\n * All switcher chrome uses the `accent` color (default {@link DEFAULT_ACCENT},\n * a violet distinct from most apps' `primary`) so it doesn't blend into the\n * content it wraps.\n *\n * Degrades gracefully. In a production build the picker chrome is dropped\n * entirely and only the first variant renders as plain content — a safety net\n * for a block that shipped without being finalized. In dev, if the recorder\n * endpoint is absent (feature off) the switcher still works as a viewer and\n * Confirm reports that recording is unavailable.\n *\n * @example Page section (default layout — full-width, stacks vertically)\n * ```tsx\n * <Variants blockId=\"hero\">\n * <Variant label=\"Split\"><section>…</section></Variant>\n * <Variant label=\"Centered\"><section>…</section></Variant>\n * </Variants>\n * ```\n *\n * @example Small inline element (hug the content)\n * ```tsx\n * <Variants blockId=\"hero-cta\" layout=\"inline\">\n * <Variant label=\"Ghost\"><Button variant=\"ghost\">Get started</Button></Variant>\n * <Variant label=\"Solid\"><Button>Get started</Button></Variant>\n * </Variants>\n * ```\n *\n * @example Custom accent\n * ```tsx\n * <Variants blockId=\"hero\" accent=\"#f43f5e\">…</Variants>\n * ```\n */\nexport function Variants({\n blockId,\n children,\n layout = \"block\",\n className,\n accent = DEFAULT_ACCENT,\n}: VariantsProps) {\n const variants = useMemo(\n () => Children.toArray(children).filter(isVariantElement),\n [children],\n );\n const [active, setActive] = useState(0);\n const [confirmState, setConfirmState] = useState<ConfirmState>(\"idle\");\n\n if (variants.length === 0) return null;\n if (!import.meta.env.DEV) return <>{variants[0]}</>;\n\n const clampedActive = Math.min(active, variants.length - 1);\n const current = variants[clampedActive];\n const label = current.props.label ?? `Variant ${clampedActive + 1}`;\n const atStart = clampedActive === 0;\n const atEnd = clampedActive === variants.length - 1;\n\n const go = (delta: number) => {\n // No wrap-around: clamp within bounds.\n setActive((i) => Math.max(0, Math.min(variants.length - 1, i + delta)));\n setConfirmState(\"idle\");\n };\n\n const confirm = async () => {\n if (confirmState === \"saving\") return;\n setConfirmState(\"saving\");\n\n // Bound the request so a hung recorder can't leave the button stuck in\n // \"saving\" forever.\n const controller = new AbortController();\n const timeout = setTimeout(() => controller.abort(), CONFIRM_TIMEOUT_MS);\n try {\n const res = await fetch(CONFIRM_ENDPOINT, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify({ blockId, chosenIndex: clampedActive, label }),\n signal: controller.signal,\n });\n // 404/403: the recorder isn't mounted (feature off or a production\n // build). Degrade to a plain viewer.\n if (res.status === 404 || res.status === 403) {\n setConfirmState(\"unavailable\");\n return;\n }\n // Any other non-OK status (e.g. a 500) is a failure the user can retry.\n setConfirmState(res.ok ? \"recorded\" : \"error\");\n } catch {\n // Network failure or timeout abort — the request never completed.\n setConfirmState(\"error\");\n } finally {\n clearTimeout(timeout);\n }\n };\n\n return (\n <div\n data-slot=\"variants\"\n // All accent chrome derives from this one variable; children read it via\n // the cascade, so the `accent` prop flows everywhere without prop-drilling.\n style={{ \"--variants-accent\": accent } as CSSProperties}\n className={cn(\n // Ring appears only on hover/focus so blocks stay calm at rest; the\n // corner dot is the resting \"in variant state\" indicator.\n \"group relative rounded-md ring-[color:var(--variants-accent)] transition-[box-shadow] duration-200\",\n layout === \"inline\" ? \"inline-block\" : \"block w-full\",\n \"hover:ring-1 focus-within:ring-1\",\n className,\n )}\n >\n {current}\n\n <StateDot\n state={confirmState}\n className=\"group-hover:pointer-events-none group-hover:opacity-0 group-focus-within:pointer-events-none group-focus-within:opacity-0\"\n />\n\n <div\n data-slot=\"variants-switcher\"\n className={cn(\n \"absolute -top-3 right-0 z-20 flex items-center gap-0.5 rounded-full border bg-background/95 px-1 py-0.5 shadow-md backdrop-blur\",\n \"border-[color-mix(in_srgb,var(--variants-accent)_40%,transparent)]\",\n \"pointer-events-none origin-top-right scale-90 opacity-0 transition-all duration-150\",\n \"group-hover:pointer-events-auto group-hover:scale-100 group-hover:opacity-100\",\n \"group-focus-within:pointer-events-auto group-focus-within:scale-100 group-focus-within:opacity-100\",\n )}\n >\n <RoundButton\n aria-label=\"Previous variant\"\n disabled={atStart}\n onClick={() => go(-1)}\n >\n <ChevronLeft className=\"size-3.5\" />\n </RoundButton>\n\n <span className=\"select-none rounded-full bg-[color-mix(in_srgb,var(--variants-accent)_15%,transparent)] px-1 text-[10px] font-semibold text-[color:var(--variants-accent)] tabular-nums\">\n {clampedActive + 1}/{variants.length}\n </span>\n\n <RoundButton\n aria-label=\"Next variant\"\n disabled={atEnd}\n onClick={() => go(1)}\n >\n <ChevronRight className=\"size-3.5\" />\n </RoundButton>\n\n <ConfirmButton state={confirmState} label={label} onClick={confirm} />\n </div>\n </div>\n );\n}\n\nfunction dotColorFor(state: ConfirmState): string {\n switch (state) {\n case \"error\":\n return \"bg-destructive\";\n case \"unavailable\":\n return \"bg-muted-foreground/40\";\n default:\n return \"bg-[color:var(--variants-accent)]\";\n }\n}\n\n/**\n * Resting corner indicator: pulses while a choice is pending, calm once\n * recorded — so a block's picked/unpicked state reads at a glance without\n * hovering.\n */\nfunction StateDot({\n state,\n className,\n}: {\n state: ConfirmState;\n className?: string;\n}) {\n const pulsing = state === \"idle\" || state === \"saving\";\n const color = dotColorFor(state);\n\n return (\n <span\n aria-hidden\n data-slot=\"variants-dot\"\n className={cn(\n \"absolute -top-1 -right-1 z-10 flex size-3 items-center justify-center transition-opacity duration-150\",\n className,\n )}\n >\n {pulsing && (\n <span\n className={cn(\n // Slow, gentle pulse (~2.5s) so it reads as an ambient hint,\n // not an alarm. Overrides tailwind's default 1s ping cadence.\n \"absolute inline-flex size-full animate-ping rounded-full opacity-50 [animation-duration:2.5s]\",\n color,\n )}\n />\n )}\n <span\n className={cn(\n \"relative inline-flex size-2.5 rounded-full ring-2 ring-background\",\n color,\n )}\n />\n </span>\n );\n}\n\nfunction RoundButton({\n children,\n disabled,\n className,\n ...props\n}: ComponentProps<\"button\">) {\n return (\n <button\n type=\"button\"\n disabled={disabled}\n className={cn(\n \"inline-flex size-6 items-center justify-center rounded-full text-muted-foreground transition-colors\",\n \"hover:bg-accent hover:text-accent-foreground\",\n \"disabled:pointer-events-none disabled:opacity-30\",\n className,\n )}\n {...props}\n >\n {children}\n </button>\n );\n}\n\n/**\n * Round tick that confirms the active variant. State is conveyed by icon +\n * color only (no text). The chosen `label` rides along in the title/aria for\n * accessibility and hover context.\n */\nfunction ConfirmButton({\n state,\n label,\n onClick,\n}: {\n state: ConfirmState;\n label: string;\n onClick: () => void;\n}) {\n const title =\n state === \"recorded\"\n ? `Recorded \"${label}\" — ask the agent to finalize`\n : state === \"unavailable\"\n ? \"Recorder unavailable\"\n : state === \"error\"\n ? \"Failed — click to retry\"\n : `Confirm \"${label}\"`;\n\n return (\n <RoundButton\n aria-label={title}\n title={title}\n disabled={state === \"saving\" || state === \"unavailable\"}\n onClick={onClick}\n className={cn(\n state === \"recorded\" &&\n \"text-[color:var(--variants-accent)] hover:bg-[color-mix(in_srgb,var(--variants-accent)_12%,transparent)] hover:text-[color:var(--variants-accent)]\",\n state === \"error\" &&\n \"text-destructive hover:bg-destructive/10 hover:text-destructive\",\n (state === \"idle\" || state === \"saving\") &&\n \"hover:bg-[color-mix(in_srgb,var(--variants-accent)_12%,transparent)] hover:text-[color:var(--variants-accent)]\",\n )}\n >\n {state === \"saving\" ? (\n <Loader2 className=\"size-3.5 animate-spin\" />\n ) : state === \"recorded\" ? (\n <CheckCheck className=\"size-3.5\" />\n ) : (\n <Check className=\"size-3.5\" />\n )}\n </RoundButton>\n );\n}\n"],"mappings":";;;;;;;;AAqBA,MAAM,mBAAmB;;AAGzB,MAAM,qBAAqB;;;;;;AAO3B,MAAM,iBAAiB;AAoCvB,SAAS,iBAAiB,MAAqD;AAC7E,QAAO,eAAe,KAAK,IAAI,KAAK,SAAS;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA6C/C,SAAgB,SAAS,EACvB,SACA,UACA,SAAS,SACT,WACA,SAAS,kBACO;CAChB,MAAM,WAAW,cACT,SAAS,QAAQ,SAAS,CAAC,OAAO,iBAAiB,EACzD,CAAC,SAAS,CACX;CACD,MAAM,CAAC,QAAQ,aAAa,SAAS,EAAE;CACvC,MAAM,CAAC,cAAc,mBAAmB,SAAuB,OAAO;AAEtE,KAAI,SAAS,WAAW,EAAG,QAAO;AAClC,KAAI,CAAC,OAAO,KAAK,IAAI,IAAK,QAAO,0CAAG,SAAS,KAAM;CAEnD,MAAM,gBAAgB,KAAK,IAAI,QAAQ,SAAS,SAAS,EAAE;CAC3D,MAAM,UAAU,SAAS;CACzB,MAAM,QAAQ,QAAQ,MAAM,SAAS,WAAW,gBAAgB;CAChE,MAAM,UAAU,kBAAkB;CAClC,MAAM,QAAQ,kBAAkB,SAAS,SAAS;CAElD,MAAM,MAAM,UAAkB;AAE5B,aAAW,MAAM,KAAK,IAAI,GAAG,KAAK,IAAI,SAAS,SAAS,GAAG,IAAI,MAAM,CAAC,CAAC;AACvE,kBAAgB,OAAO;;CAGzB,MAAM,UAAU,YAAY;AAC1B,MAAI,iBAAiB,SAAU;AAC/B,kBAAgB,SAAS;EAIzB,MAAM,aAAa,IAAI,iBAAiB;EACxC,MAAM,UAAU,iBAAiB,WAAW,OAAO,EAAE,mBAAmB;AACxE,MAAI;GACF,MAAM,MAAM,MAAM,MAAM,kBAAkB;IACxC,QAAQ;IACR,SAAS,EAAE,gBAAgB,oBAAoB;IAC/C,MAAM,KAAK,UAAU;KAAE;KAAS,aAAa;KAAe;KAAO,CAAC;IACpE,QAAQ,WAAW;IACpB,CAAC;AAGF,OAAI,IAAI,WAAW,OAAO,IAAI,WAAW,KAAK;AAC5C,oBAAgB,cAAc;AAC9B;;AAGF,mBAAgB,IAAI,KAAK,aAAa,QAAQ;UACxC;AAEN,mBAAgB,QAAQ;YAChB;AACR,gBAAa,QAAQ;;;AAIzB,QACE,qBAAC;EACC,aAAU;EAGV,OAAO,EAAE,qBAAqB,QAAQ;EACtC,WAAW,GAGT,sGACA,WAAW,WAAW,iBAAiB,gBACvC,oCACA,UACD;;GAEA;GAED,oBAAC;IACC,OAAO;IACP,WAAU;KACV;GAEF,qBAAC;IACC,aAAU;IACV,WAAW,GACT,mIACA,sEACA,uFACA,iFACA,qGACD;;KAED,oBAAC;MACC,cAAW;MACX,UAAU;MACV,eAAe,GAAG,GAAG;gBAErB,oBAAC,eAAY,WAAU,aAAa;OACxB;KAEd,qBAAC;MAAK,WAAU;;OACb,gBAAgB;OAAE;OAAE,SAAS;;OACzB;KAEP,oBAAC;MACC,cAAW;MACX,UAAU;MACV,eAAe,GAAG,EAAE;gBAEpB,oBAAC,gBAAa,WAAU,aAAa;OACzB;KAEd,oBAAC;MAAc,OAAO;MAAqB;MAAO,SAAS;OAAW;;KAClE;;GACF;;AAIV,SAAS,YAAY,OAA6B;AAChD,SAAQ,OAAR;EACE,KAAK,QACH,QAAO;EACT,KAAK,cACH,QAAO;EACT,QACE,QAAO;;;;;;;;AASb,SAAS,SAAS,EAChB,OACA,aAIC;CACD,MAAM,UAAU,UAAU,UAAU,UAAU;CAC9C,MAAM,QAAQ,YAAY,MAAM;AAEhC,QACE,qBAAC;EACC;EACA,aAAU;EACV,WAAW,GACT,yGACA,UACD;aAEA,WACC,oBAAC,UACC,WAAW,GAGT,iGACA,MACD,GACD,EAEJ,oBAAC,UACC,WAAW,GACT,qEACA,MACD,GACD;GACG;;AAIX,SAAS,YAAY,EACnB,UACA,UACA,WACA,GAAG,SACwB;AAC3B,QACE,oBAAC;EACC,MAAK;EACK;EACV,WAAW,GACT,uGACA,gDACA,oDACA,UACD;EACD,GAAI;EAEH;GACM;;;;;;;AASb,SAAS,cAAc,EACrB,OACA,OACA,WAKC;CACD,MAAM,QACJ,UAAU,aACN,aAAa,MAAM,iCACnB,UAAU,gBACR,yBACA,UAAU,UACR,4BACA,YAAY,MAAM;AAE5B,QACE,oBAAC;EACC,cAAY;EACL;EACP,UAAU,UAAU,YAAY,UAAU;EACjC;EACT,WAAW,GACT,UAAU,cACR,sJACF,UAAU,WACR,oEACD,UAAU,UAAU,UAAU,aAC7B,iHACH;YAEA,UAAU,WACT,oBAAC,WAAQ,WAAU,0BAA0B,GAC3C,UAAU,aACZ,oBAAC,cAAW,WAAU,aAAa,GAEnC,oBAAC,SAAM,WAAU,aAAa;GAEpB"}
|
|
@@ -1118,6 +1118,7 @@ declare const pluginManifestSchema: z.ZodObject<{
|
|
|
1118
1118
|
license: z.ZodOptional<z.ZodString>;
|
|
1119
1119
|
onSetupMessage: z.ZodOptional<z.ZodString>;
|
|
1120
1120
|
hidden: z.ZodOptional<z.ZodBoolean>;
|
|
1121
|
+
devOnly: z.ZodOptional<z.ZodBoolean>;
|
|
1121
1122
|
stability: z.ZodOptional<z.ZodEnum<{
|
|
1122
1123
|
beta: "beta";
|
|
1123
1124
|
ga: "ga";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"manifest.d.ts","names":[],"sources":["../../src/schemas/manifest.ts"],"mappings":";;;cAsPa,yBAAA,EAAyB,CAAA,CAAA,qBAAA,EAAA,CAAA,CAAA,SAAA;;;;;;;;;;;;;;;;;;;;;;cA8FzB,wBAAA,EAAwB,CAAA,CAAA,SAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;cAkQxB,4BAAA,EAA4B,CAAA,CAAA,SAAA;;;;;cAoE5B,oBAAA,EAAoB,CAAA,CAAA,SAAA
|
|
1
|
+
{"version":3,"file":"manifest.d.ts","names":[],"sources":["../../src/schemas/manifest.ts"],"mappings":";;;cAsPa,yBAAA,EAAyB,CAAA,CAAA,qBAAA,EAAA,CAAA,CAAA,SAAA;;;;;;;;;;;;;;;;;;;;;;cA8FzB,wBAAA,EAAwB,CAAA,CAAA,SAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;cAkQxB,4BAAA,EAA4B,CAAA,CAAA,SAAA;;;;;cAoE5B,oBAAA,EAAoB,CAAA,CAAA,SAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;KAqgBrB,mBAAA,GAAsB,CAAA,CAAE,KAAA,QAAa,yBAAA;AAAA,KACrC,kBAAA,GAAqB,CAAA,CAAE,KAAA,QAAa,wBAAA;AAAA,KAIpC,sBAAA,GAAyB,CAAA,CAAE,KAAA,QAC9B,4BAAA;AAAA,KAEG,cAAA,GAAiB,CAAA,CAAE,KAAA,QAAa,oBAAA"}
|
package/dist/schemas/manifest.js
CHANGED
|
@@ -334,6 +334,7 @@ const pluginManifestSchema = z.object({
|
|
|
334
334
|
license: z.string().optional().describe("SPDX license identifier"),
|
|
335
335
|
onSetupMessage: z.string().optional().describe("Message displayed to the user after project initialization. Use this to inform about manual setup steps (e.g. environment variables, resource provisioning)."),
|
|
336
336
|
hidden: z.boolean().optional().describe("When true, this plugin is excluded from the template plugins manifest (appkit.plugins.json) during sync."),
|
|
337
|
+
devOnly: z.boolean().optional().describe("When true, this plugin is only registered when NODE_ENV === 'development'. In any other environment createApp skips it entirely (not constructed, no routes, resources not validated). Use for dev-only tooling that must never run in a deployed app."),
|
|
337
338
|
stability: z.enum(["beta", "ga"]).optional().describe("Plugin stability level. Beta plugins may have breaking API changes between minor releases but are on a path to GA. GA (general availability) plugins follow semver strictly."),
|
|
338
339
|
scaffolding: z.object({ rules: pluginScaffoldingRulesSchema.optional().describe("Structured rules for scaffolding agents declared at the plugin level.") }).strict().optional().describe("Plugin-level scaffolding metadata consumed by scaffolding agents. Symmetric with template-level `scaffolding`.")
|
|
339
340
|
}).strict().describe("Schema for Databricks AppKit plugin manifest files. Defines plugin metadata, resource requirements, and configuration options.");
|