@pipe0/react 0.2.0 → 0.2.1

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.
Files changed (98) hide show
  1. package/CHANGELOG.md +8 -0
  2. package/dist/components/compound/pipe-form/errors.d.mts.map +1 -1
  3. package/dist/components/compound/pipe-form/errors.mjs +5 -4
  4. package/dist/components/compound/pipe-form/errors.mjs.map +1 -1
  5. package/dist/components/compound/pipe-form/root.d.mts +3 -1
  6. package/dist/components/compound/pipe-form/root.d.mts.map +1 -1
  7. package/dist/components/compound/pipe-form/root.mjs +5 -3
  8. package/dist/components/compound/pipe-form/root.mjs.map +1 -1
  9. package/dist/components/compound/search-form/errors.d.mts.map +1 -1
  10. package/dist/components/compound/search-form/errors.mjs +5 -4
  11. package/dist/components/compound/search-form/errors.mjs.map +1 -1
  12. package/dist/components/compound/search-form/root.d.mts +3 -1
  13. package/dist/components/compound/search-form/root.d.mts.map +1 -1
  14. package/dist/components/compound/search-form/root.mjs +5 -3
  15. package/dist/components/compound/search-form/root.mjs.map +1 -1
  16. package/dist/components/defaults/adapters/context-select-input.mjs +1 -1
  17. package/dist/components/defaults/adapters/context-select-input.mjs.map +1 -1
  18. package/dist/components/defaults/adapters/index.d.mts.map +1 -1
  19. package/dist/components/defaults/adapters/index.mjs +8 -5
  20. package/dist/components/defaults/adapters/index.mjs.map +1 -1
  21. package/dist/components/defaults/adapters/int-input.mjs.map +1 -1
  22. package/dist/components/defaults/adapters/loose-object-input.mjs +111 -0
  23. package/dist/components/defaults/adapters/loose-object-input.mjs.map +1 -0
  24. package/dist/components/defaults/adapters/pipes-run-if-input.mjs +68 -55
  25. package/dist/components/defaults/adapters/pipes-run-if-input.mjs.map +1 -1
  26. package/dist/components/defaults/adapters/providers-input.mjs.map +1 -1
  27. package/dist/components/defaults/adapters/search-payload-input.mjs +18 -0
  28. package/dist/components/defaults/adapters/search-payload-input.mjs.map +1 -0
  29. package/dist/components/defaults/adapters/select-input.mjs +46 -27
  30. package/dist/components/defaults/adapters/select-input.mjs.map +1 -1
  31. package/dist/components/defaults/catalog/card-derived.d.mts +1 -1
  32. package/dist/components/defaults/catalog/card-derived.d.mts.map +1 -1
  33. package/dist/components/defaults/catalog/card-derived.mjs +6 -2
  34. package/dist/components/defaults/catalog/card-derived.mjs.map +1 -1
  35. package/dist/components/defaults/layout/field-wrapper.d.mts.map +1 -1
  36. package/dist/components/defaults/layout/field-wrapper.mjs +11 -5
  37. package/dist/components/defaults/layout/field-wrapper.mjs.map +1 -1
  38. package/dist/components/defaults/layout/group.mjs +1 -1
  39. package/dist/components/internal/LiquidEditor/LiquidEditor.mjs.map +1 -1
  40. package/dist/components/internal/form-level-errors.mjs +4 -3
  41. package/dist/components/internal/form-level-errors.mjs.map +1 -1
  42. package/dist/components/internal/icons.mjs +27 -1
  43. package/dist/components/internal/icons.mjs.map +1 -1
  44. package/dist/components/ui/alert.d.mts +47 -0
  45. package/dist/components/ui/alert.d.mts.map +1 -0
  46. package/dist/components/ui/alert.mjs +66 -0
  47. package/dist/components/ui/alert.mjs.map +1 -0
  48. package/dist/context/form-context.d.mts +21 -0
  49. package/dist/context/form-context.d.mts.map +1 -0
  50. package/dist/context/form-context.mjs +11 -1
  51. package/dist/context/form-context.mjs.map +1 -1
  52. package/dist/context/form-provider.d.mts +3 -1
  53. package/dist/context/form-provider.d.mts.map +1 -1
  54. package/dist/context/form-provider.mjs +8 -2
  55. package/dist/context/form-provider.mjs.map +1 -1
  56. package/dist/hooks/use-effect-catalog-table.d.mts.map +1 -1
  57. package/dist/hooks/use-effect-catalog-table.mjs +2 -2
  58. package/dist/hooks/use-effect-catalog-table.mjs.map +1 -1
  59. package/dist/hooks/use-form-core.mjs +7 -4
  60. package/dist/hooks/use-form-core.mjs.map +1 -1
  61. package/dist/hooks/use-pipe-catalog-table.d.mts +8 -8
  62. package/dist/hooks/use-pipe-catalog-table.d.mts.map +1 -1
  63. package/dist/hooks/use-pipe-catalog-table.mjs +2 -2
  64. package/dist/hooks/use-pipe-catalog-table.mjs.map +1 -1
  65. package/dist/hooks/use-pipe-form.d.mts.map +1 -1
  66. package/dist/hooks/use-pipe-form.mjs +18 -19
  67. package/dist/hooks/use-pipe-form.mjs.map +1 -1
  68. package/dist/hooks/use-search-catalog-table.d.mts +6 -6
  69. package/dist/hooks/use-search-form.d.mts.map +1 -1
  70. package/dist/hooks/use-search-form.mjs +18 -18
  71. package/dist/hooks/use-search-form.mjs.map +1 -1
  72. package/dist/hooks/use-sheet-effect-form.d.mts.map +1 -1
  73. package/dist/hooks/use-sheet-effect-form.mjs +18 -19
  74. package/dist/hooks/use-sheet-effect-form.mjs.map +1 -1
  75. package/dist/index.d.mts +4 -2
  76. package/dist/index.mjs +3 -1
  77. package/dist/styles/pipe0-form.css +1 -1
  78. package/dist/types/adapters.d.mts +22 -1
  79. package/dist/types/adapters.d.mts.map +1 -1
  80. package/dist/types/catalog-adapters.d.mts +1 -1
  81. package/dist/types/field-props.d.mts +15 -13
  82. package/dist/types/field-props.d.mts.map +1 -1
  83. package/dist/types/form-customization.d.mts +2 -25
  84. package/dist/utils/build-section-handlers.mjs +7 -73
  85. package/dist/utils/build-section-handlers.mjs.map +1 -1
  86. package/dist/widgets/token-pricing-badge.d.mts +1 -0
  87. package/dist/widgets/token-pricing-badge.mjs +55 -0
  88. package/dist/widgets/token-pricing-badge.mjs.map +1 -0
  89. package/dist/widgets/widget-strip.d.mts.map +1 -1
  90. package/dist/widgets/widget-strip.mjs +1 -0
  91. package/dist/widgets/widget-strip.mjs.map +1 -1
  92. package/dist/widgets/widget-view.d.mts.map +1 -1
  93. package/dist/widgets/widget-view.mjs +6 -0
  94. package/dist/widgets/widget-view.mjs.map +1 -1
  95. package/package.json +2 -2
  96. package/dist/components/defaults/adapters/key-value-list-input.mjs +0 -102
  97. package/dist/components/defaults/adapters/key-value-list-input.mjs.map +0 -1
  98. package/dist/types/form-customization.d.mts.map +0 -1
@@ -1 +1 @@
1
- {"version":3,"file":"card-derived.mjs","names":[],"sources":["../../../../src/components/defaults/catalog/card-derived.tsx"],"sourcesContent":["import { Check, Coins, Copy, ExternalLink, ListChecks, ListPlus } from \"lucide-react\";\nimport { type ReactNode, useState } from \"react\";\nimport type { AnyCardData } from \"../../../context/catalog-card-context.js\";\nimport {\n useAnyCatalogCardOptional,\n useAnyCatalogContextOptional,\n} from \"../../../context/catalog-card-context.js\";\nimport { useCatalogConfig } from \"../../../context/catalog-config-context.js\";\nimport { cn } from \"../../../lib/utils.js\";\nimport { Popover, PopoverContent, PopoverTrigger } from \"../../ui/popover.js\";\nimport { CatalogCardBadge, type CatalogCardBadgeProps } from \"./card-primitives.js\";\n\n/* -------------------------------------------------------------------------- */\n/* Credit badge — \"Starts at X / result|search|page\" or \"Free\" */\n/* -------------------------------------------------------------------------- */\n\nexport interface CatalogCreditBadgeProps {\n /** Override the auto-bound credit amount. */\n creditAmount?: number;\n /** Override the auto-bound cost mode. */\n costMode?: \"per_result\" | \"per_search\" | \"per_page\";\n freeLabel?: ReactNode;\n creditPrefix?: ReactNode;\n className?: string;\n disabled?: boolean;\n variant?: CatalogCardBadgeProps[\"variant\"];\n}\n\n/**\n * Displays the starting credit cost for the surrounding card. Self-binds to\n * `card.startingCreditAmount` + `card.costMode` from card context unless\n * overridden via props.\n */\nexport function CatalogCreditBadge({\n creditAmount,\n costMode,\n freeLabel = \"Free\",\n creditPrefix = \"Starts at\",\n disabled = true,\n className,\n variant,\n}: CatalogCreditBadgeProps) {\n const card = useAnyCatalogCardOptional()?.card;\n const amount =\n creditAmount ?? (card && \"startingCreditAmount\" in card ? card.startingCreditAmount : 0);\n const mode = costMode ?? (card && \"costMode\" in card ? card.costMode : \"per_result\");\n const denom = mode === \"per_result\" ? \"result\" : mode === \"per_search\" ? \"search\" : \"page\";\n return (\n <CatalogCardBadge\n disabled={disabled}\n variant={variant}\n className={cn(\"pz:whitespace-nowrap\", className)}\n >\n {amount > 0 ? (\n <span className=\"pz:inline-flex pz:items-center pz:gap-0.5\">\n {creditPrefix ? <span className=\"pz:mr-1\">{creditPrefix}</span> : null}\n <span>{amount}</span>\n <Coins className=\"pz:size-3\" />\n <span>/ {denom}</span>\n </span>\n ) : (\n freeLabel\n )}\n </CatalogCardBadge>\n );\n}\n\n/* -------------------------------------------------------------------------- */\n/* Field badge — dropdown listing input or output fields, click to filter */\n/* -------------------------------------------------------------------------- */\n\nexport interface CatalogFieldBadgeState {\n fields: string[];\n isOpen: boolean;\n setOpen: (open: boolean) => void;\n /** Calls onSelectField (or the auto-wired catalog filter) and closes the popover. */\n onSelect: (fieldName: string) => void;\n isFieldAvailable: (fieldName: string) => boolean;\n}\n\nexport interface CatalogFieldBadgeProps {\n fieldType: \"input\" | \"output\";\n /** Override the auto-bound fields list. */\n fields?: string[];\n /** Override the auto-wired filter handler. */\n onSelectField?: (fieldName: string) => void;\n /** Returns true if the field has any matching cards. Defaults to a reverse-index lookup on the catalog. */\n isFieldAvailable?: (fieldName: string) => boolean;\n label?: ReactNode;\n fieldIcon?: (fieldName: string) => ReactNode;\n className?: string;\n variant?: CatalogCardBadgeProps[\"variant\"];\n /** Render the entire dropdown UI yourself. Receives the merged state. */\n render?: (state: CatalogFieldBadgeState) => ReactNode;\n}\n\n/**\n * Dropdown that lists a card's input or output fields, with click-to-filter\n * wiring. By default, clicking a field filters the catalog by that field\n * (`addColumnFilter(\"inputFields\"|\"outputFields\", field)`); pass `onSelectField`\n * to override (e.g. inverted-filter UX).\n */\nexport function CatalogFieldBadge({\n fieldType,\n fields,\n onSelectField,\n isFieldAvailable,\n label,\n fieldIcon,\n className,\n variant = \"outline\",\n render,\n}: CatalogFieldBadgeProps) {\n const [open, setOpen] = useState(false);\n const card = useAnyCatalogCardOptional()?.card;\n const ctx = useAnyCatalogContextOptional();\n\n const resolvedFields = fields ?? deriveCardFields(card, fieldType);\n\n const handleSelect =\n onSelectField ??\n ((field: string) => {\n ctx?.addColumnFilter(fieldType === \"input\" ? \"inputFields\" : \"outputFields\", field);\n });\n\n const handleAvailable =\n isFieldAvailable ??\n ((field: string) => {\n if (!ctx) return true;\n const map =\n fieldType === \"input\"\n ? (ctx as { pipeIdsByInputField?: Record<string, unknown[]> }).pipeIdsByInputField\n : pickOutputIndex(ctx);\n if (!map) return true;\n return !!map[field];\n });\n\n if (render) {\n return (\n <>\n {render({\n fields: resolvedFields,\n isOpen: open,\n setOpen,\n onSelect: (field: string) => {\n handleSelect(field);\n setOpen(false);\n },\n isFieldAvailable: handleAvailable,\n })}\n </>\n );\n }\n\n if (!resolvedFields.length) return null;\n const Icon = fieldType === \"input\" ? ListPlus : ListChecks;\n const text = label ?? (fieldType === \"input\" ? \"Show inputs\" : \"Show outputs\");\n return (\n <Popover open={open} onOpenChange={setOpen}>\n <PopoverTrigger\n render={\n <CatalogCardBadge\n variant={variant}\n className={cn(\n \"pz:font-normal pz:text-muted-foreground pz:hover:text-foreground\",\n className,\n )}\n >\n <Icon className=\"pz:size-3\" />\n {text}\n </CatalogCardBadge>\n }\n />\n <PopoverContent align=\"start\" side=\"bottom\" className=\"pz:w-auto pz:min-w-40 pz:p-1\">\n <ul\n data-p0=\"catalog-card-field-badge-list\"\n className=\"pz:flex pz:flex-col pz:gap-0.5 pz:list-none pz:m-0 pz:p-0\"\n >\n {resolvedFields.map((field) => {\n const available = handleAvailable(field);\n return (\n <li key={field} className=\"pz:flex\">\n <button\n type=\"button\"\n onClick={(e) => {\n e.stopPropagation();\n handleSelect(field);\n setOpen(false);\n }}\n className={cn(\n \"pz:w-full pz:text-sm pz:text-left pz:py-1 pz:px-2 pz:rounded pz:flex pz:items-center pz:gap-2 pz:transition-all\",\n available\n ? \"pz:text-muted-foreground pz:hover:text-foreground pz:hover:bg-muted\"\n : \"pz:text-muted-foreground/50 pz:cursor-not-allowed\",\n )}\n data-available={available}\n >\n {fieldIcon?.(field)}\n {field}\n </button>\n </li>\n );\n })}\n </ul>\n </PopoverContent>\n </Popover>\n );\n}\n\nfunction deriveCardFields(card: AnyCardData | undefined, fieldType: \"input\" | \"output\"): string[] {\n if (!card) return [];\n if (fieldType === \"output\") {\n return (\"defaultOutputFields\" in card ? card.defaultOutputFields : []) ?? [];\n }\n if (\"defaultInputFields\" in card) {\n return card.defaultInputFields.map((f) => f.name);\n }\n return [];\n}\n\nfunction pickOutputIndex(ctx: unknown): Record<string, unknown[]> | undefined {\n const c = ctx as {\n pipeIdsByOutputField?: Record<string, unknown[]>;\n searchIdsByOutputField?: Record<string, unknown[]>;\n };\n return c.pipeIdsByOutputField ?? c.searchIdsByOutputField;\n}\n\n/* -------------------------------------------------------------------------- */\n/* Docs badge — external link to provider docs */\n/* -------------------------------------------------------------------------- */\n\nexport interface CatalogDocsBadgeProps {\n /** Base URL prepended to the card's docPath. */\n baseUrl?: string;\n /** Override the full URL (skips baseUrl + card.docPath composition). */\n href?: string;\n label?: ReactNode;\n className?: string;\n variant?: CatalogCardBadgeProps[\"variant\"];\n}\n\nexport function CatalogDocsBadge({\n baseUrl,\n href,\n label = \"Go to docs\",\n className,\n variant = \"outline\",\n}: CatalogDocsBadgeProps) {\n const card = useAnyCatalogCardOptional()?.card;\n const docPath = card && \"docPath\" in card ? card.docPath : undefined;\n const resolvedHref = href ?? (baseUrl && docPath ? `${baseUrl}${docPath}` : docPath);\n if (!resolvedHref) return null;\n return (\n <a target=\"_blank\" href={resolvedHref} rel=\"noreferrer\" onClick={(e) => e.stopPropagation()}>\n <CatalogCardBadge\n variant={variant}\n className={cn(\n \"pz:font-normal pz:text-muted-foreground pz:hover:text-foreground\",\n className,\n )}\n >\n <ExternalLink className=\"pz:size-3\" />\n {label}\n </CatalogCardBadge>\n </a>\n );\n}\n\n/* -------------------------------------------------------------------------- */\n/* Copy-id input — small input with a copy button */\n/* -------------------------------------------------------------------------- */\n\nexport interface CatalogCopyIdProps {\n /** Override the auto-bound id. Defaults to `card.pipeId` / `card.searchId` / `card.searchesId`. */\n value?: string;\n className?: string;\n}\n\nexport function CatalogCopyId({ value, className }: CatalogCopyIdProps) {\n const { classNames } = useCatalogConfig();\n const card = useAnyCatalogCardOptional()?.card;\n const resolved = value ?? deriveCardId(card);\n const [copied, setCopied] = useState(false);\n\n if (!resolved) return null;\n\n const handleCopy = (e: React.MouseEvent) => {\n e.stopPropagation();\n e.preventDefault();\n void navigator.clipboard?.writeText(resolved).then(() => {\n setCopied(true);\n setTimeout(() => setCopied(false), 1500);\n });\n };\n\n return (\n <div\n data-p0=\"catalog-card-copy-id\"\n className={cn(\n \"pz:flex pz:items-center pz:gap-2 pz:rounded-md pz:border pz:border-input pz:bg-background pz:px-2 pz:py-1\",\n classNames?.copyId,\n className,\n )}\n onClick={(e) => e.stopPropagation()}\n >\n <code className=\"pz:flex-1 pz:text-xs pz:text-muted-foreground pz:truncate pz:font-mono\">\n {resolved}\n </code>\n <button\n type=\"button\"\n onClick={handleCopy}\n aria-label=\"Copy\"\n className=\"pz:inline-flex pz:items-center pz:justify-center pz:size-6 pz:rounded pz:text-muted-foreground pz:hover:text-foreground pz:hover:bg-muted pz:transition-all\"\n >\n {copied ? <Check className=\"pz:size-3\" /> : <Copy className=\"pz:size-3\" />}\n </button>\n </div>\n );\n}\n\nfunction deriveCardId(card: AnyCardData | undefined): string | undefined {\n if (!card) return undefined;\n if (\"pipeId\" in card) return card.pipeId;\n if (\"searchesId\" in card) return card.searchesId;\n if (\"searchId\" in card) return card.searchId;\n if (\"effectId\" in card) return card.effectId;\n return undefined;\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"card-derived.mjs","names":[],"sources":["../../../../src/components/defaults/catalog/card-derived.tsx"],"sourcesContent":["import { Check, Coins, Copy, ExternalLink, ListChecks, ListPlus } from \"lucide-react\";\nimport { type ReactNode, useState } from \"react\";\nimport type { AnyCardData } from \"../../../context/catalog-card-context.js\";\nimport {\n useAnyCatalogCardOptional,\n useAnyCatalogContextOptional,\n} from \"../../../context/catalog-card-context.js\";\nimport { useCatalogConfig } from \"../../../context/catalog-config-context.js\";\nimport { cn } from \"../../../lib/utils.js\";\nimport { Popover, PopoverContent, PopoverTrigger } from \"../../ui/popover.js\";\nimport { CatalogCardBadge, type CatalogCardBadgeProps } from \"./card-primitives.js\";\n\n/* -------------------------------------------------------------------------- */\n/* Credit badge — \"Starts at X / result|search|page\" or \"Free\" */\n/* -------------------------------------------------------------------------- */\n\nexport interface CatalogCreditBadgeProps {\n /** Override the auto-bound credit amount. */\n creditAmount?: number;\n /** Override the auto-bound cost mode. */\n costMode?: \"per_result\" | \"per_search\" | \"per_page\" | \"usage\";\n freeLabel?: ReactNode;\n creditPrefix?: ReactNode;\n className?: string;\n disabled?: boolean;\n variant?: CatalogCardBadgeProps[\"variant\"];\n}\n\n/**\n * Displays the starting credit cost for the surrounding card. Self-binds to\n * `card.startingCreditAmount` + `card.costMode` from card context unless\n * overridden via props.\n */\nexport function CatalogCreditBadge({\n creditAmount,\n costMode,\n freeLabel = \"Free\",\n creditPrefix = \"Starts at\",\n disabled = true,\n className,\n variant,\n}: CatalogCreditBadgeProps) {\n const card = useAnyCatalogCardOptional()?.card;\n const amount =\n creditAmount ?? (card && \"startingCreditAmount\" in card ? card.startingCreditAmount : 0);\n const mode = costMode ?? (card && \"costMode\" in card ? card.costMode : \"per_result\");\n const denom = mode === \"per_result\" ? \"result\" : mode === \"per_search\" ? \"search\" : \"page\";\n // Round away floating-point noise; flat per-use prices are already clean.\n const display = Math.round(amount * 1000) / 1000;\n return (\n <CatalogCardBadge\n disabled={disabled}\n variant={variant}\n className={cn(\"pz:whitespace-nowrap\", className)}\n >\n {mode === \"usage\" ? (\n <span className=\"pz:inline-flex pz:items-center pz:gap-1\">\n <Coins className=\"pz:size-3\" />\n <span>Usage</span>\n </span>\n ) : display > 0 ? (\n <span className=\"pz:inline-flex pz:items-center pz:gap-0.5\">\n {creditPrefix ? <span className=\"pz:mr-1\">{creditPrefix}</span> : null}\n <span>{display}</span>\n <Coins className=\"pz:size-3\" />\n <span>/ {denom}</span>\n </span>\n ) : (\n freeLabel\n )}\n </CatalogCardBadge>\n );\n}\n\n/* -------------------------------------------------------------------------- */\n/* Field badge — dropdown listing input or output fields, click to filter */\n/* -------------------------------------------------------------------------- */\n\nexport interface CatalogFieldBadgeState {\n fields: string[];\n isOpen: boolean;\n setOpen: (open: boolean) => void;\n /** Calls onSelectField (or the auto-wired catalog filter) and closes the popover. */\n onSelect: (fieldName: string) => void;\n isFieldAvailable: (fieldName: string) => boolean;\n}\n\nexport interface CatalogFieldBadgeProps {\n fieldType: \"input\" | \"output\";\n /** Override the auto-bound fields list. */\n fields?: string[];\n /** Override the auto-wired filter handler. */\n onSelectField?: (fieldName: string) => void;\n /** Returns true if the field has any matching cards. Defaults to a reverse-index lookup on the catalog. */\n isFieldAvailable?: (fieldName: string) => boolean;\n label?: ReactNode;\n fieldIcon?: (fieldName: string) => ReactNode;\n className?: string;\n variant?: CatalogCardBadgeProps[\"variant\"];\n /** Render the entire dropdown UI yourself. Receives the merged state. */\n render?: (state: CatalogFieldBadgeState) => ReactNode;\n}\n\n/**\n * Dropdown that lists a card's input or output fields, with click-to-filter\n * wiring. By default, clicking a field filters the catalog by that field\n * (`addColumnFilter(\"inputFields\"|\"outputFields\", field)`); pass `onSelectField`\n * to override (e.g. inverted-filter UX).\n */\nexport function CatalogFieldBadge({\n fieldType,\n fields,\n onSelectField,\n isFieldAvailable,\n label,\n fieldIcon,\n className,\n variant = \"outline\",\n render,\n}: CatalogFieldBadgeProps) {\n const [open, setOpen] = useState(false);\n const card = useAnyCatalogCardOptional()?.card;\n const ctx = useAnyCatalogContextOptional();\n\n const resolvedFields = fields ?? deriveCardFields(card, fieldType);\n\n const handleSelect =\n onSelectField ??\n ((field: string) => {\n ctx?.addColumnFilter(fieldType === \"input\" ? \"inputFields\" : \"outputFields\", field);\n });\n\n const handleAvailable =\n isFieldAvailable ??\n ((field: string) => {\n if (!ctx) return true;\n const map =\n fieldType === \"input\"\n ? (ctx as { pipeIdsByInputField?: Record<string, unknown[]> }).pipeIdsByInputField\n : pickOutputIndex(ctx);\n if (!map) return true;\n return !!map[field];\n });\n\n if (render) {\n return (\n <>\n {render({\n fields: resolvedFields,\n isOpen: open,\n setOpen,\n onSelect: (field: string) => {\n handleSelect(field);\n setOpen(false);\n },\n isFieldAvailable: handleAvailable,\n })}\n </>\n );\n }\n\n if (!resolvedFields.length) return null;\n const Icon = fieldType === \"input\" ? ListPlus : ListChecks;\n const text = label ?? (fieldType === \"input\" ? \"Show inputs\" : \"Show outputs\");\n return (\n <Popover open={open} onOpenChange={setOpen}>\n <PopoverTrigger\n render={\n <CatalogCardBadge\n variant={variant}\n className={cn(\n \"pz:font-normal pz:text-muted-foreground pz:hover:text-foreground\",\n className,\n )}\n >\n <Icon className=\"pz:size-3\" />\n {text}\n </CatalogCardBadge>\n }\n />\n <PopoverContent align=\"start\" side=\"bottom\" className=\"pz:w-auto pz:min-w-40 pz:p-1\">\n <ul\n data-p0=\"catalog-card-field-badge-list\"\n className=\"pz:flex pz:flex-col pz:gap-0.5 pz:list-none pz:m-0 pz:p-0\"\n >\n {resolvedFields.map((field) => {\n const available = handleAvailable(field);\n return (\n <li key={field} className=\"pz:flex\">\n <button\n type=\"button\"\n onClick={(e) => {\n e.stopPropagation();\n handleSelect(field);\n setOpen(false);\n }}\n className={cn(\n \"pz:w-full pz:text-sm pz:text-left pz:py-1 pz:px-2 pz:rounded pz:flex pz:items-center pz:gap-2 pz:transition-all\",\n available\n ? \"pz:text-muted-foreground pz:hover:text-foreground pz:hover:bg-muted\"\n : \"pz:text-muted-foreground/50 pz:cursor-not-allowed\",\n )}\n data-available={available}\n >\n {fieldIcon?.(field)}\n {field}\n </button>\n </li>\n );\n })}\n </ul>\n </PopoverContent>\n </Popover>\n );\n}\n\nfunction deriveCardFields(card: AnyCardData | undefined, fieldType: \"input\" | \"output\"): string[] {\n if (!card) return [];\n if (fieldType === \"output\") {\n return (\"defaultOutputFields\" in card ? card.defaultOutputFields : []) ?? [];\n }\n if (\"defaultInputFields\" in card) {\n return card.defaultInputFields.map((f) => f.name);\n }\n return [];\n}\n\nfunction pickOutputIndex(ctx: unknown): Record<string, unknown[]> | undefined {\n const c = ctx as {\n pipeIdsByOutputField?: Record<string, unknown[]>;\n searchIdsByOutputField?: Record<string, unknown[]>;\n };\n return c.pipeIdsByOutputField ?? c.searchIdsByOutputField;\n}\n\n/* -------------------------------------------------------------------------- */\n/* Docs badge — external link to provider docs */\n/* -------------------------------------------------------------------------- */\n\nexport interface CatalogDocsBadgeProps {\n /** Base URL prepended to the card's docPath. */\n baseUrl?: string;\n /** Override the full URL (skips baseUrl + card.docPath composition). */\n href?: string;\n label?: ReactNode;\n className?: string;\n variant?: CatalogCardBadgeProps[\"variant\"];\n}\n\nexport function CatalogDocsBadge({\n baseUrl,\n href,\n label = \"Go to docs\",\n className,\n variant = \"outline\",\n}: CatalogDocsBadgeProps) {\n const card = useAnyCatalogCardOptional()?.card;\n const docPath = card && \"docPath\" in card ? card.docPath : undefined;\n const resolvedHref = href ?? (baseUrl && docPath ? `${baseUrl}${docPath}` : docPath);\n if (!resolvedHref) return null;\n return (\n <a target=\"_blank\" href={resolvedHref} rel=\"noreferrer\" onClick={(e) => e.stopPropagation()}>\n <CatalogCardBadge\n variant={variant}\n className={cn(\n \"pz:font-normal pz:text-muted-foreground pz:hover:text-foreground\",\n className,\n )}\n >\n <ExternalLink className=\"pz:size-3\" />\n {label}\n </CatalogCardBadge>\n </a>\n );\n}\n\n/* -------------------------------------------------------------------------- */\n/* Copy-id input — small input with a copy button */\n/* -------------------------------------------------------------------------- */\n\nexport interface CatalogCopyIdProps {\n /** Override the auto-bound id. Defaults to `card.pipeId` / `card.searchId` / `card.searchesId`. */\n value?: string;\n className?: string;\n}\n\nexport function CatalogCopyId({ value, className }: CatalogCopyIdProps) {\n const { classNames } = useCatalogConfig();\n const card = useAnyCatalogCardOptional()?.card;\n const resolved = value ?? deriveCardId(card);\n const [copied, setCopied] = useState(false);\n\n if (!resolved) return null;\n\n const handleCopy = (e: React.MouseEvent) => {\n e.stopPropagation();\n e.preventDefault();\n void navigator.clipboard?.writeText(resolved).then(() => {\n setCopied(true);\n setTimeout(() => setCopied(false), 1500);\n });\n };\n\n return (\n <div\n data-p0=\"catalog-card-copy-id\"\n className={cn(\n \"pz:flex pz:items-center pz:gap-2 pz:rounded-md pz:border pz:border-input pz:bg-background pz:px-2 pz:py-1\",\n classNames?.copyId,\n className,\n )}\n onClick={(e) => e.stopPropagation()}\n >\n <code className=\"pz:flex-1 pz:text-xs pz:text-muted-foreground pz:truncate pz:font-mono\">\n {resolved}\n </code>\n <button\n type=\"button\"\n onClick={handleCopy}\n aria-label=\"Copy\"\n className=\"pz:inline-flex pz:items-center pz:justify-center pz:size-6 pz:rounded pz:text-muted-foreground pz:hover:text-foreground pz:hover:bg-muted pz:transition-all\"\n >\n {copied ? <Check className=\"pz:size-3\" /> : <Copy className=\"pz:size-3\" />}\n </button>\n </div>\n );\n}\n\nfunction deriveCardId(card: AnyCardData | undefined): string | undefined {\n if (!card) return undefined;\n if (\"pipeId\" in card) return card.pipeId;\n if (\"searchesId\" in card) return card.searchesId;\n if (\"searchId\" in card) return card.searchId;\n if (\"effectId\" in card) return card.effectId;\n return undefined;\n}\n"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"field-wrapper.d.mts","names":[],"sources":["../../../../src/components/defaults/layout/field-wrapper.tsx"],"mappings":";;;UAQiB,wBAAA;EACf,KAAA,EAAO,aAAA;EACP,QAAA;EACA,QAAA;AAAA;AAAA,UAGe,wBAAA,SACP,SAAA,CAAU,cAAA,QAAsB,wBAAA;EACxC,KAAA,EAAO,aAAA;AAAA"}
1
+ {"version":3,"file":"field-wrapper.d.mts","names":[],"sources":["../../../../src/components/defaults/layout/field-wrapper.tsx"],"mappings":";;;UASiB,wBAAA;EACf,KAAA,EAAO,aAAA;EACP,QAAA;EACA,QAAA;AAAA;AAAA,UAGe,wBAAA,SACP,SAAA,CAAU,cAAA,QAAsB,wBAAA;EACxC,KAAA,EAAO,aAAA;AAAA"}
@@ -1,14 +1,16 @@
1
1
  import { cn } from "../../../lib/utils.mjs";
2
- import { useFormConfig } from "../../../context/form-context.mjs";
2
+ import { useFormAlert, useFormConfig } from "../../../context/form-context.mjs";
3
3
  import { HoverInfo } from "../../hover-info.mjs";
4
4
  import { RichText } from "../../rich-text.mjs";
5
5
  import { mergeProps } from "@base-ui/react/merge-props";
6
6
  import { useRender } from "@base-ui/react/use-render";
7
7
  import { Fragment, jsx, jsxs } from "react/jsx-runtime";
8
+ import { Asterisk } from "lucide-react";
8
9
 
9
10
  //#region src/components/defaults/layout/field-wrapper.tsx
10
11
  function DefaultFieldWrapper({ field, children, className, render, ...props }) {
11
12
  const { classNames } = useFormConfig();
13
+ const Alert = useFormAlert();
12
14
  const hasError = !!field.error;
13
15
  const isDisabled = field.disabled;
14
16
  const defaultContent = /* @__PURE__ */ jsxs(Fragment, { children: [
@@ -16,11 +18,14 @@ function DefaultFieldWrapper({ field, children, className, render, ...props }) {
16
18
  className: "pz:flex pz:flex-col pz:gap-1",
17
19
  children: [/* @__PURE__ */ jsxs("div", {
18
20
  className: "pz:flex pz:items-center pz:gap-1.5",
19
- children: [field.label && /* @__PURE__ */ jsx("label", {
21
+ children: [field.label && /* @__PURE__ */ jsxs("label", {
20
22
  "data-p0": "label",
21
23
  htmlFor: field.id,
22
24
  className: classNames?.label ?? cn("pz:text-sm pz:leading-none pz:font-medium pz:select-none", hasError && "pz:text-destructive"),
23
- children: /* @__PURE__ */ jsx(RichText, { children: field.label })
25
+ children: [/* @__PURE__ */ jsx(RichText, { children: field.label }), field.meta.required && /* @__PURE__ */ jsx(Asterisk, {
26
+ "aria-label": "required",
27
+ className: "pz:ml-0.5 pz:inline-block pz:size-3 pz:align-top pz:text-primary"
28
+ })]
24
29
  }), field.info && /* @__PURE__ */ jsx(HoverInfo, { children: /* @__PURE__ */ jsx(RichText, { children: field.info }) })]
25
30
  }), field.description && /* @__PURE__ */ jsx("p", {
26
31
  "data-p0": "description",
@@ -32,9 +37,10 @@ function DefaultFieldWrapper({ field, children, className, render, ...props }) {
32
37
  className: "pz:opacity-60 pz:pointer-events-none",
33
38
  children
34
39
  }) : children,
35
- isDisabled && field.disabledReason && /* @__PURE__ */ jsx("div", {
40
+ isDisabled && field.disabledReason && /* @__PURE__ */ jsx(Alert, {
41
+ variant: "info",
36
42
  "data-p0": "disabled-reason",
37
- className: classNames?.disabledReason ?? "pz:rounded-md pz:border pz:border-input pz:bg-muted/40 pz:px-3 pz:py-2 pz:text-xs pz:text-muted-foreground",
43
+ className: classNames?.disabledReason,
38
44
  children: /* @__PURE__ */ jsx(RichText, { children: field.disabledReason })
39
45
  }),
40
46
  hasError && /* @__PURE__ */ jsx("span", {
@@ -1 +1 @@
1
- {"version":3,"file":"field-wrapper.mjs","names":[],"sources":["../../../../src/components/defaults/layout/field-wrapper.tsx"],"sourcesContent":["import { mergeProps } from \"@base-ui/react/merge-props\";\nimport { useRender } from \"@base-ui/react/use-render\";\nimport { useFormConfig } from \"../../../context/form-context.js\";\nimport { cn } from \"../../../lib/utils.js\";\nimport type { AnyFieldProps } from \"../../../types/field-props.js\";\nimport { HoverInfo } from \"../../hover-info.js\";\nimport { RichText } from \"../../rich-text.js\";\n\nexport interface DefaultFieldWrapperState {\n field: AnyFieldProps;\n disabled: boolean;\n hasError: boolean;\n}\n\nexport interface DefaultFieldWrapperProps\n extends useRender.ComponentProps<\"div\", DefaultFieldWrapperState> {\n field: AnyFieldProps;\n}\n\nexport function DefaultFieldWrapper({\n field,\n children,\n className,\n render,\n ...props\n}: DefaultFieldWrapperProps) {\n const { classNames } = useFormConfig();\n const hasError = !!field.error;\n const isDisabled = field.disabled;\n\n // Boolean toggles render their label inline with the switch (settings-row\n // pattern), so the wrapper's label/description block is suppressed for them.\n const inlineLabel = field.kind === \"boolean_input\";\n\n const defaultContent = (\n <>\n {!inlineLabel && (field.label || field.description || field.info) && (\n <div className=\"pz:flex pz:flex-col pz:gap-1\">\n <div className=\"pz:flex pz:items-center pz:gap-1.5\">\n {field.label && (\n <label\n data-p0=\"label\"\n htmlFor={field.id}\n className={\n classNames?.label ??\n cn(\n \"pz:text-sm pz:leading-none pz:font-medium pz:select-none\",\n hasError && \"pz:text-destructive\",\n )\n }\n >\n <RichText>{field.label}</RichText>\n </label>\n )}\n {field.info && (\n <HoverInfo>\n <RichText>{field.info}</RichText>\n </HoverInfo>\n )}\n </div>\n {field.description && (\n <p\n data-p0=\"description\"\n className={classNames?.description ?? \"pz:text-xs pz:text-muted-foreground\"}\n >\n <RichText>{field.description}</RichText>\n </p>\n )}\n </div>\n )}\n {isDisabled ? (\n <div className=\"pz:opacity-60 pz:pointer-events-none\">{children}</div>\n ) : (\n children\n )}\n {isDisabled && field.disabledReason && (\n <div\n data-p0=\"disabled-reason\"\n className={\n classNames?.disabledReason ??\n \"pz:rounded-md pz:border pz:border-input pz:bg-muted/40 pz:px-3 pz:py-2 pz:text-xs pz:text-muted-foreground\"\n }\n >\n <RichText>{field.disabledReason}</RichText>\n </div>\n )}\n {hasError && (\n <span\n data-p0=\"error\"\n className={classNames?.error ?? \"pz:text-destructive pz:text-xs pz:font-medium\"}\n role=\"alert\"\n >\n <RichText>{field.error}</RichText>\n </span>\n )}\n </>\n );\n\n return useRender({\n defaultTagName: \"div\",\n render,\n state: { field, disabled: isDisabled, hasError },\n stateAttributesMapping: {\n field: () => null,\n },\n props: mergeProps<\"div\">(\n {\n className: cn(\n classNames?.field ?? \"pz:grid pz:gap-2\",\n isDisabled && classNames?.fieldDisabled,\n className,\n ),\n children: defaultContent,\n ...({\n \"data-p0\": \"field\",\n \"data-p0-field\": field.path,\n \"data-p0-kind\": field.kind,\n ...(isDisabled ? { \"data-p0-disabled\": \"true\", \"aria-disabled\": \"true\" } : {}),\n } as Record<string, string>),\n },\n props,\n ),\n });\n}\n"],"mappings":";;;;;;;;;AAmBA,SAAgB,oBAAoB,EAClC,OACA,UACA,WACA,QACA,GAAG,SACwB;CAC3B,MAAM,EAAE,eAAe,eAAe;CACtC,MAAM,WAAW,CAAC,CAAC,MAAM;CACzB,MAAM,aAAa,MAAM;CAMzB,MAAM,iBACJ;EACG,EAJe,MAAM,SAAS,qBAIb,MAAM,SAAS,MAAM,eAAe,MAAM,SAC1D,qBAAC,OAAD;GAAK,WAAU;aAAf,CACE,qBAAC,OAAD;IAAK,WAAU;cAAf,CACG,MAAM,SACL,oBAAC,SAAD;KACE,WAAQ;KACR,SAAS,MAAM;KACf,WACE,YAAY,SACZ,GACE,4DACA,YAAY,sBACb;eAGH,oBAAC,UAAD,YAAW,MAAM,OAAiB;KAC5B,GAET,MAAM,QACL,oBAAC,WAAD,YACE,oBAAC,UAAD,YAAW,MAAM,MAAgB,GACvB,EAEV;OACL,MAAM,eACL,oBAAC,KAAD;IACE,WAAQ;IACR,WAAW,YAAY,eAAe;cAEtC,oBAAC,UAAD,YAAW,MAAM,aAAuB;IACtC,EAEF;;EAEP,aACC,oBAAC,OAAD;GAAK,WAAU;GAAwC;GAAe,IAEtE;EAED,cAAc,MAAM,kBACnB,oBAAC,OAAD;GACE,WAAQ;GACR,WACE,YAAY,kBACZ;aAGF,oBAAC,UAAD,YAAW,MAAM,gBAA0B;GACvC;EAEP,YACC,oBAAC,QAAD;GACE,WAAQ;GACR,WAAW,YAAY,SAAS;GAChC,MAAK;aAEL,oBAAC,UAAD,YAAW,MAAM,OAAiB;GAC7B;EAER;AAGL,QAAO,UAAU;EACf,gBAAgB;EAChB;EACA,OAAO;GAAE;GAAO,UAAU;GAAY;GAAU;EAChD,wBAAwB,EACtB,aAAa,MACd;EACD,OAAO,WACL;GACE,WAAW,GACT,YAAY,SAAS,oBACrB,cAAc,YAAY,eAC1B,UACD;GACD,UAAU;GAER,WAAW;GACX,iBAAiB,MAAM;GACvB,gBAAgB,MAAM;GACtB,GAAI,aAAa;IAAE,oBAAoB;IAAQ,iBAAiB;IAAQ,GAAG,EAAE;GAEhF,EACD,MACD;EACF,CAAC"}
1
+ {"version":3,"file":"field-wrapper.mjs","names":[],"sources":["../../../../src/components/defaults/layout/field-wrapper.tsx"],"sourcesContent":["import { mergeProps } from \"@base-ui/react/merge-props\";\nimport { useRender } from \"@base-ui/react/use-render\";\nimport { Asterisk } from \"lucide-react\";\nimport { useFormAlert, useFormConfig } from \"../../../context/form-context.js\";\nimport { cn } from \"../../../lib/utils.js\";\nimport type { AnyFieldProps } from \"../../../types/field-props.js\";\nimport { HoverInfo } from \"../../hover-info.js\";\nimport { RichText } from \"../../rich-text.js\";\n\nexport interface DefaultFieldWrapperState {\n field: AnyFieldProps;\n disabled: boolean;\n hasError: boolean;\n}\n\nexport interface DefaultFieldWrapperProps\n extends useRender.ComponentProps<\"div\", DefaultFieldWrapperState> {\n field: AnyFieldProps;\n}\n\nexport function DefaultFieldWrapper({\n field,\n children,\n className,\n render,\n ...props\n}: DefaultFieldWrapperProps) {\n const { classNames } = useFormConfig();\n const Alert = useFormAlert();\n const hasError = !!field.error;\n const isDisabled = field.disabled;\n\n // Boolean toggles render their label inline with the switch (settings-row\n // pattern), so the wrapper's label/description block is suppressed for them.\n const inlineLabel = field.kind === \"boolean_input\";\n\n const defaultContent = (\n <>\n {!inlineLabel && (field.label || field.description || field.info) && (\n <div className=\"pz:flex pz:flex-col pz:gap-1\">\n <div className=\"pz:flex pz:items-center pz:gap-1.5\">\n {field.label && (\n <label\n data-p0=\"label\"\n htmlFor={field.id}\n className={\n classNames?.label ??\n cn(\n \"pz:text-sm pz:leading-none pz:font-medium pz:select-none\",\n hasError && \"pz:text-destructive\",\n )\n }\n >\n <RichText>{field.label}</RichText>\n {field.meta.required && (\n <Asterisk\n aria-label=\"required\"\n className=\"pz:ml-0.5 pz:inline-block pz:size-3 pz:align-top pz:text-primary\"\n />\n )}\n </label>\n )}\n {field.info && (\n <HoverInfo>\n <RichText>{field.info}</RichText>\n </HoverInfo>\n )}\n </div>\n {field.description && (\n <p\n data-p0=\"description\"\n className={classNames?.description ?? \"pz:text-xs pz:text-muted-foreground\"}\n >\n <RichText>{field.description}</RichText>\n </p>\n )}\n </div>\n )}\n {isDisabled ? (\n <div className=\"pz:opacity-60 pz:pointer-events-none\">{children}</div>\n ) : (\n children\n )}\n {isDisabled && field.disabledReason && (\n <Alert variant=\"info\" data-p0=\"disabled-reason\" className={classNames?.disabledReason}>\n <RichText>{field.disabledReason}</RichText>\n </Alert>\n )}\n {hasError && (\n <span\n data-p0=\"error\"\n className={classNames?.error ?? \"pz:text-destructive pz:text-xs pz:font-medium\"}\n role=\"alert\"\n >\n <RichText>{field.error}</RichText>\n </span>\n )}\n </>\n );\n\n return useRender({\n defaultTagName: \"div\",\n render,\n state: { field, disabled: isDisabled, hasError },\n stateAttributesMapping: {\n field: () => null,\n },\n props: mergeProps<\"div\">(\n {\n className: cn(\n classNames?.field ?? \"pz:grid pz:gap-2\",\n isDisabled && classNames?.fieldDisabled,\n className,\n ),\n children: defaultContent,\n ...({\n \"data-p0\": \"field\",\n \"data-p0-field\": field.path,\n \"data-p0-kind\": field.kind,\n ...(isDisabled ? { \"data-p0-disabled\": \"true\", \"aria-disabled\": \"true\" } : {}),\n } as Record<string, string>),\n },\n props,\n ),\n });\n}\n"],"mappings":";;;;;;;;;;AAoBA,SAAgB,oBAAoB,EAClC,OACA,UACA,WACA,QACA,GAAG,SACwB;CAC3B,MAAM,EAAE,eAAe,eAAe;CACtC,MAAM,QAAQ,cAAc;CAC5B,MAAM,WAAW,CAAC,CAAC,MAAM;CACzB,MAAM,aAAa,MAAM;CAMzB,MAAM,iBACJ;EACG,EAJe,MAAM,SAAS,qBAIb,MAAM,SAAS,MAAM,eAAe,MAAM,SAC1D,qBAAC,OAAD;GAAK,WAAU;aAAf,CACE,qBAAC,OAAD;IAAK,WAAU;cAAf,CACG,MAAM,SACL,qBAAC,SAAD;KACE,WAAQ;KACR,SAAS,MAAM;KACf,WACE,YAAY,SACZ,GACE,4DACA,YAAY,sBACb;eARL,CAWE,oBAAC,UAAD,YAAW,MAAM,OAAiB,GACjC,MAAM,KAAK,YACV,oBAAC,UAAD;MACE,cAAW;MACX,WAAU;MACV,EAEE;QAET,MAAM,QACL,oBAAC,WAAD,YACE,oBAAC,UAAD,YAAW,MAAM,MAAgB,GACvB,EAEV;OACL,MAAM,eACL,oBAAC,KAAD;IACE,WAAQ;IACR,WAAW,YAAY,eAAe;cAEtC,oBAAC,UAAD,YAAW,MAAM,aAAuB;IACtC,EAEF;;EAEP,aACC,oBAAC,OAAD;GAAK,WAAU;GAAwC;GAAe,IAEtE;EAED,cAAc,MAAM,kBACnB,oBAAC,OAAD;GAAO,SAAQ;GAAO,WAAQ;GAAkB,WAAW,YAAY;aACrE,oBAAC,UAAD,YAAW,MAAM,gBAA0B;GACrC;EAET,YACC,oBAAC,QAAD;GACE,WAAQ;GACR,WAAW,YAAY,SAAS;GAChC,MAAK;aAEL,oBAAC,UAAD,YAAW,MAAM,OAAiB;GAC7B;EAER;AAGL,QAAO,UAAU;EACf,gBAAgB;EAChB;EACA,OAAO;GAAE;GAAO,UAAU;GAAY;GAAU;EAChD,wBAAwB,EACtB,aAAa,MACd;EACD,OAAO,WACL;GACE,WAAW,GACT,YAAY,SAAS,oBACrB,cAAc,YAAY,eAC1B,UACD;GACD,UAAU;GAER,WAAW;GACX,iBAAiB,MAAM;GACvB,gBAAgB,MAAM;GACtB,GAAI,aAAa;IAAE,oBAAoB;IAAQ,iBAAiB;IAAQ,GAAG,EAAE;GAEhF,EACD,MACD;EACF,CAAC"}
@@ -1,7 +1,7 @@
1
1
  import { cn } from "../../../lib/utils.mjs";
2
+ import { IconChevronDown } from "../../internal/icons.mjs";
2
3
  import { useFormConfig } from "../../../context/form-context.mjs";
3
4
  import { IconGlyph } from "../../../widgets/icon-glyph.mjs";
4
- import { IconChevronDown } from "../../internal/icons.mjs";
5
5
  import { HoverInfo } from "../../hover-info.mjs";
6
6
  import { Badge } from "../../ui/badge.mjs";
7
7
  import { mergeProps } from "@base-ui/react/merge-props";
@@ -1 +1 @@
1
- {"version":3,"file":"LiquidEditor.mjs","names":[],"sources":["../../../../src/components/internal/LiquidEditor/LiquidEditor.tsx"],"sourcesContent":["import {\n type PipesFieldDefinitionWithName,\n RECORD_FIELD_TYPES,\n type RecordFieldType,\n} from \"@pipe0/base\";\nimport type { EditorProps } from \"@tiptap/pm/view\";\nimport { EditorContent, EditorContext, useEditor } from \"@tiptap/react\";\nimport StarterKit from \"@tiptap/starter-kit\";\nimport { useCallback, useEffect, useMemo, useState } from \"react\";\nimport { useAsyncRemoteSource } from \"../../../hooks/use-async-remote-source.js\";\nimport { cn } from \"../../../lib/utils.js\";\nimport type { ConstantSuggestion, SecretSuggestion } from \"../../../types/field-props.js\";\nimport { FieldLegend, type LegendEntry } from \"../field-legend.js\";\nimport { SuggestionMenu } from \"../suggestion-menu/suggestion-menu.js\";\nimport type { SuggestionItem } from \"../suggestion-menu/suggestion-menu-types.js\";\nimport { type ChipHit, TagChipDecoration } from \"../tag-chip-decoration.js\";\nimport { ChipEditPopover, type ChipEditTarget } from \"./ChipEditPopover.js\";\nimport {\n buildReferenceItems,\n parseQuery,\n type ReferenceContext,\n SECTION_CAP,\n UnifiedReferencePicker,\n} from \"./UnifiedReferencePicker.js\";\n\nexport type DirectiveKind = \"output\";\n\nexport interface LiquidEditorProps {\n value: string;\n onChange: (v: string) => void;\n inputFields: PipesFieldDefinitionWithName[];\n /**\n * Per-keystroke async searcher for secrets. Called from the `/` reference\n * picker as the user types. Calls are debounced and race-guarded — only\n * the response for the latest query is rendered.\n */\n searchSecrets?: (query: string) => Promise<SecretSuggestion[]>;\n /**\n * Per-keystroke async searcher for constants. Mirrors `searchSecrets`.\n */\n searchConstants?: (query: string) => Promise<ConstantSuggestion[]>;\n multiline?: boolean;\n /**\n * When true, the editor renders within `min-h`/`max-h` bounds. When\n * false, callers control the height via `className`. Default: true.\n */\n autoGrow?: boolean;\n directives?: DirectiveKind[];\n expectedFieldType?: RecordFieldType;\n placeholder?: string;\n className?: string;\n editorProps?: EditorProps;\n /**\n * Suppress the per-editor legend. Used by `key_value_list_input` which\n * renders a single legend below the entire list rather than per-cell.\n */\n hideLegend?: boolean;\n}\n\nfunction escapeHtml(s: string): string {\n return s.replace(/&/g, \"&amp;\").replace(/</g, \"&lt;\").replace(/>/g, \"&gt;\");\n}\n\n/**\n * Reconciles single- and multi-line text into Tiptap-friendly HTML.\n * - Single-line: collapses whitespace runs containing newlines into a\n * single space and renders as one paragraph.\n * - Multi-line: paragraphs separated by blank lines (`\\n\\n+`); soft\n * breaks within a paragraph render as `<br>`. Leading spaces on each\n * line are preserved with `&nbsp;` so JSON-shaped payloads round-trip\n * through the editor.\n */\nfunction textToTiptapHTML(text: string, multiline: boolean): string {\n if (!multiline) {\n return `<p>${escapeHtml(text.replace(/\\s*\\n+\\s*/g, \" \"))}</p>`;\n }\n return escapeHtml(text)\n .split(/\\n\\n+/)\n .map((block) => {\n const lines = block.split(/\\n/);\n const htmlLines = lines\n .map((line) => line.replace(/^ +/, (spaces) => \"&nbsp;\".repeat(spaces.length)))\n .join(\"<br>\");\n return `<p>${htmlLines}</p>`;\n })\n .join(\"\");\n}\n\nconst OUTPUT_TEMPLATE = (fieldType: RecordFieldType): string => {\n if (fieldType === \"json\") {\n return `{% output FIELD_NAME, type: \"json\", schema: \"SCHEMA_NAME\", description: \"\" %}`;\n }\n return `{% output FIELD_NAME, type: \"${fieldType}\", description: \"\" %}`;\n};\n\n/**\n * Single editor surface for every form field that accepts Liquid tags.\n * Two triggers, two cognitive categories:\n *\n * - `/` opens a unified reference picker (Fields, Secrets, Constants).\n * Prefix syntax `/f/`, `/s/`, `/c/` filters to one source. Picking\n * emits the corresponding `{{ … }}` Liquid Output.\n *\n * - `@` opens a directives picker (only when `directives.length > 0`).\n * Today the only directive is `output`, which inserts a templated\n * `{% output FIELD_NAME, type: \"...\", description: \"\" %}` block.\n *\n * Chips render via the `TagChipDecoration` extension. Click or\n * Enter/Space on a chip mounts the contextual `ChipEditPopover`.\n *\n * Backwards compat: the persisted value is plain Liquid text,\n * byte-identical to what the legacy `TagEditor` / `TextPromptEditor`\n * produced. No engine, analyzer, or metadata changes.\n */\nexport function LiquidEditor({\n value,\n onChange,\n inputFields,\n searchSecrets,\n searchConstants,\n multiline = false,\n autoGrow = true,\n directives = [],\n expectedFieldType,\n placeholder,\n className,\n editorProps,\n hideLegend = false,\n}: LiquidEditorProps) {\n const blockSeparator = multiline ? \"\\n\" : \"\";\n const supportsOutput = directives.includes(\"output\");\n const hasSecretsResolver = !!searchSecrets;\n const hasConstantsResolver = !!searchConstants;\n\n const secretSource = useAsyncRemoteSource<SecretSuggestion>({ search: searchSecrets });\n const constantSource = useAsyncRemoteSource<ConstantSuggestion>({ search: searchConstants });\n\n // Warm caches once per resolver identity so the empty-query open is hot.\n useEffect(() => {\n secretSource.prefetch();\n }, [secretSource.prefetch]);\n\n useEffect(() => {\n constantSource.prefetch();\n }, [constantSource.prefetch]);\n\n const [chipTarget, setChipTarget] = useState<ChipEditTarget | null>(null);\n\n const tagChipExtension = useMemo(\n () =>\n TagChipDecoration.configure({\n onChipClick: (hit: ChipHit, el: HTMLElement) => {\n setChipTarget({\n kind: hit.kind,\n raw: hit.raw,\n from: hit.from,\n to: hit.to,\n rect: el.getBoundingClientRect(),\n });\n },\n }),\n [],\n );\n\n const editor = useEditor({\n extensions: [\n StarterKit.configure({ hardBreak: !multiline ? false : undefined }),\n tagChipExtension,\n ],\n parseOptions: { preserveWhitespace: \"full\" },\n editorProps: {\n ...editorProps,\n attributes: {\n class: cn(\n \"pz:px-2.5 pz:py-1 pz:text-sm pz:outline-none pz:break-words\",\n multiline\n ? autoGrow\n ? \"pz:min-h-24 pz:max-h-96 pz:overflow-auto pz:whitespace-pre-wrap\"\n : \"pz:overflow-auto pz:whitespace-pre-wrap\"\n : \"pz:min-h-8\",\n className,\n ),\n ...(placeholder ? { \"data-placeholder\": placeholder } : {}),\n ...editorProps?.attributes,\n },\n handleKeyDown(view, event) {\n if (editorProps?.handleKeyDown?.(view, event)) return true;\n // Single-line: Enter must not split the document. Multi-line: let\n // StarterKit handle Enter so paragraphs and blocks behave normally.\n if (!multiline && event.key === \"Enter\") return true;\n return false;\n },\n },\n content: textToTiptapHTML(value || \"\", multiline),\n onUpdate({ editor }) {\n onChange(editor.getText({ blockSeparator }));\n },\n });\n\n // Sync the editor's document when `value` changes from outside (e.g.\n // form reset, programmatic setValue). `useEditor` only reads `content`\n // at mount; without this hook the visible UI drifts from form state.\n // The early-return short-circuits the loop that the editor's own\n // `onUpdate` would otherwise create.\n useEffect(() => {\n if (!editor) return;\n const current = editor.getText({ blockSeparator });\n if (current === (value ?? \"\")) return;\n editor.commands.setContent(textToTiptapHTML(value ?? \"\", multiline), {\n emitUpdate: false,\n });\n }, [editor, value, multiline, blockSeparator]);\n\n const insertField = useCallback((name: string) => `{{ ${name} }}`, []);\n\n // Tracks the current query in the open reference picker. Drives the\n // `liveItems` recomputation below — when the async sources resolve, we\n // re-render the picker against this query without waiting for Tiptap to\n // re-call items().\n const [referenceQuery, setReferenceQuery] = useState(\"\");\n\n // In sectioned (empty-query) view, cap each kind at SECTION_CAP visible\n // rows. Users see a compact summary and type to filter; the act of\n // filtering switches to flat mode where all matches are shown.\n // Caps are applied at this layer (not inside the picker) so the array\n // passed to SuggestionMenu matches what's rendered — keyboard nav\n // operates on the visible set and never lands on a hidden row.\n const buildVisibleItems = useCallback(\n (\n query: string,\n ): {\n items: SuggestionItem<ReferenceContext>[];\n overflow: Record<ReferenceContext[\"kind\"], number>;\n } => {\n const all = buildReferenceItems(\n query,\n {\n inputFields,\n secretSuggestions: secretSource.items,\n constantSuggestions: constantSource.items,\n },\n expectedFieldType,\n insertField,\n );\n const { prefix, residual } = parseQuery(query);\n const isFlat = !!residual.trim() || prefix !== null;\n if (isFlat) {\n return { items: all, overflow: { field: 0, secret: 0, constant: 0 } };\n }\n const fields = all.filter((i) => i.context?.kind === \"field\");\n const secrets = all.filter((i) => i.context?.kind === \"secret\");\n const constants = all.filter((i) => i.context?.kind === \"constant\");\n return {\n items: [\n ...fields.slice(0, SECTION_CAP),\n ...secrets.slice(0, SECTION_CAP),\n ...constants.slice(0, SECTION_CAP),\n ],\n overflow: {\n field: Math.max(0, fields.length - SECTION_CAP),\n secret: Math.max(0, secrets.length - SECTION_CAP),\n constant: Math.max(0, constants.length - SECTION_CAP),\n },\n };\n },\n [inputFields, expectedFieldType, insertField, secretSource.items, constantSource.items],\n );\n\n const referenceItems = useCallback(\n ({ query }: { query: string }): SuggestionItem<ReferenceContext>[] => {\n setReferenceQuery(query);\n // Fire-and-forget: results land via React state in `secretSource.items`\n // / `constantSource.items` and trigger a re-render. The popup reads\n // them through `liveItems` (see below).\n secretSource.ensure(query);\n constantSource.ensure(query);\n return buildVisibleItems(query).items;\n },\n [secretSource.ensure, constantSource.ensure, buildVisibleItems],\n );\n\n // Live items derived from the current query + cached source items. This is\n // recomputed whenever an async source resolves (which updates\n // `secretSource.items` / `constantSource.items` via setState). Passed to\n // SuggestionMenu via `liveItems` so the open popup re-renders without\n // needing the user to type — Tiptap's items() callback alone cannot\n // deliver async results that arrive between keystrokes.\n const { items: liveReferenceItems, overflow: liveOverflow } = useMemo(\n () => buildVisibleItems(referenceQuery),\n [referenceQuery, buildVisibleItems],\n );\n\n const directiveItems = useCallback(\n () =>\n RECORD_FIELD_TYPES.map<SuggestionItem>((fieldType) => ({\n title: `${fieldType}`,\n keywords: [fieldType, \"output\"],\n onSelect: ({ editor: ed, range }) => {\n ed.chain().focus().insertContentAt(range, OUTPUT_TEMPLATE(fieldType)).run();\n },\n })),\n [],\n );\n\n const legendEntries: LegendEntry[] = [];\n legendEntries.push({ key: \"/\", label: \"to insert a reference\" });\n if (supportsOutput) legendEntries.push({ key: \"@\", label: \"to add an output field\" });\n\n return (\n <EditorContext.Provider value={{ editor }}>\n <EditorContent editor={editor} />\n\n {!hideLegend && <FieldLegend entries={legendEntries} />}\n\n <SuggestionMenu\n editor={editor}\n char=\"/\"\n pluginKey=\"liquidEditorReferencePicker\"\n items={referenceItems}\n liveItems={liveReferenceItems}\n >\n {(props) => (\n <UnifiedReferencePicker\n items={props.items as SuggestionItem<ReferenceContext>[]}\n selectedIndex={props.selectedIndex}\n onSelect={props.onSelect as (item: SuggestionItem<ReferenceContext>) => void}\n query={props.query}\n hasSecretsResolver={hasSecretsResolver}\n hasConstantsResolver={hasConstantsResolver}\n inputFieldsCount={inputFields.length}\n secretsPending={secretSource.pending}\n constantsPending={constantSource.pending}\n overflow={liveOverflow}\n />\n )}\n </SuggestionMenu>\n\n {supportsOutput && (\n <SuggestionMenu\n editor={editor}\n char=\"@\"\n pluginKey=\"liquidEditorDirectivePicker\"\n items={directiveItems}\n >\n {({ items, selectedIndex, onSelect }) => (\n <div className=\"pz:flex pz:flex-col pz:gap-0.5 pz:p-1 pz:min-w-56\" role=\"listbox\">\n <div className=\"pz:px-2 pz:pt-1 pz:pb-0.5 pz:text-[10px] pz:font-medium pz:uppercase pz:tracking-wide pz:text-muted-foreground\">\n Add output declaration\n </div>\n {items.map((item, index) => (\n <button\n key={item.title}\n type=\"button\"\n role=\"option\"\n aria-selected={selectedIndex === index}\n onClick={() => onSelect(item)}\n className={cn(\n \"pz:flex pz:w-full pz:items-center pz:rounded-sm pz:px-2 pz:py-1.5 pz:text-sm pz:text-left pz:cursor-pointer\",\n selectedIndex === index\n ? \"pz:bg-accent pz:text-accent-foreground\"\n : \"pz:hover:bg-accent pz:hover:text-accent-foreground\",\n )}\n >\n {item.title}\n </button>\n ))}\n </div>\n )}\n </SuggestionMenu>\n )}\n\n {chipTarget && editor && (\n <ChipEditPopover editor={editor} target={chipTarget} onClose={() => setChipTarget(null)} />\n )}\n </EditorContext.Provider>\n );\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"LiquidEditor.mjs","names":[],"sources":["../../../../src/components/internal/LiquidEditor/LiquidEditor.tsx"],"sourcesContent":["import {\n type PipesFieldDefinitionWithName,\n RECORD_FIELD_TYPES,\n type RecordFieldType,\n} from \"@pipe0/base\";\nimport type { EditorProps } from \"@tiptap/pm/view\";\nimport { EditorContent, EditorContext, useEditor } from \"@tiptap/react\";\nimport StarterKit from \"@tiptap/starter-kit\";\nimport { useCallback, useEffect, useMemo, useState } from \"react\";\nimport { useAsyncRemoteSource } from \"../../../hooks/use-async-remote-source.js\";\nimport { cn } from \"../../../lib/utils.js\";\nimport type { ConstantSuggestion, SecretSuggestion } from \"../../../types/field-props.js\";\nimport { FieldLegend, type LegendEntry } from \"../field-legend.js\";\nimport { SuggestionMenu } from \"../suggestion-menu/suggestion-menu.js\";\nimport type { SuggestionItem } from \"../suggestion-menu/suggestion-menu-types.js\";\nimport { type ChipHit, TagChipDecoration } from \"../tag-chip-decoration.js\";\nimport { ChipEditPopover, type ChipEditTarget } from \"./ChipEditPopover.js\";\nimport {\n buildReferenceItems,\n parseQuery,\n type ReferenceContext,\n SECTION_CAP,\n UnifiedReferencePicker,\n} from \"./UnifiedReferencePicker.js\";\n\nexport type DirectiveKind = \"output\";\n\nexport interface LiquidEditorProps {\n value: string;\n onChange: (v: string) => void;\n inputFields: PipesFieldDefinitionWithName[];\n /**\n * Per-keystroke async searcher for secrets. Called from the `/` reference\n * picker as the user types. Calls are debounced and race-guarded — only\n * the response for the latest query is rendered.\n */\n searchSecrets?: (query: string) => Promise<SecretSuggestion[]>;\n /**\n * Per-keystroke async searcher for constants. Mirrors `searchSecrets`.\n */\n searchConstants?: (query: string) => Promise<ConstantSuggestion[]>;\n multiline?: boolean;\n /**\n * When true, the editor renders within `min-h`/`max-h` bounds. When\n * false, callers control the height via `className`. Default: true.\n */\n autoGrow?: boolean;\n directives?: DirectiveKind[];\n expectedFieldType?: RecordFieldType;\n placeholder?: string;\n className?: string;\n editorProps?: EditorProps;\n /**\n * Suppress the per-editor legend. Used by `loose_object_input` which\n * renders a single legend below the entire list rather than per-cell.\n */\n hideLegend?: boolean;\n}\n\nfunction escapeHtml(s: string): string {\n return s.replace(/&/g, \"&amp;\").replace(/</g, \"&lt;\").replace(/>/g, \"&gt;\");\n}\n\n/**\n * Reconciles single- and multi-line text into Tiptap-friendly HTML.\n * - Single-line: collapses whitespace runs containing newlines into a\n * single space and renders as one paragraph.\n * - Multi-line: paragraphs separated by blank lines (`\\n\\n+`); soft\n * breaks within a paragraph render as `<br>`. Leading spaces on each\n * line are preserved with `&nbsp;` so JSON-shaped payloads round-trip\n * through the editor.\n */\nfunction textToTiptapHTML(text: string, multiline: boolean): string {\n if (!multiline) {\n return `<p>${escapeHtml(text.replace(/\\s*\\n+\\s*/g, \" \"))}</p>`;\n }\n return escapeHtml(text)\n .split(/\\n\\n+/)\n .map((block) => {\n const lines = block.split(/\\n/);\n const htmlLines = lines\n .map((line) => line.replace(/^ +/, (spaces) => \"&nbsp;\".repeat(spaces.length)))\n .join(\"<br>\");\n return `<p>${htmlLines}</p>`;\n })\n .join(\"\");\n}\n\nconst OUTPUT_TEMPLATE = (fieldType: RecordFieldType): string => {\n if (fieldType === \"json\") {\n return `{% output FIELD_NAME, type: \"json\", schema: \"SCHEMA_NAME\", description: \"\" %}`;\n }\n return `{% output FIELD_NAME, type: \"${fieldType}\", description: \"\" %}`;\n};\n\n/**\n * Single editor surface for every form field that accepts Liquid tags.\n * Two triggers, two cognitive categories:\n *\n * - `/` opens a unified reference picker (Fields, Secrets, Constants).\n * Prefix syntax `/f/`, `/s/`, `/c/` filters to one source. Picking\n * emits the corresponding `{{ … }}` Liquid Output.\n *\n * - `@` opens a directives picker (only when `directives.length > 0`).\n * Today the only directive is `output`, which inserts a templated\n * `{% output FIELD_NAME, type: \"...\", description: \"\" %}` block.\n *\n * Chips render via the `TagChipDecoration` extension. Click or\n * Enter/Space on a chip mounts the contextual `ChipEditPopover`.\n *\n * Backwards compat: the persisted value is plain Liquid text,\n * byte-identical to what the legacy `TagEditor` / `TextPromptEditor`\n * produced. No engine, analyzer, or metadata changes.\n */\nexport function LiquidEditor({\n value,\n onChange,\n inputFields,\n searchSecrets,\n searchConstants,\n multiline = false,\n autoGrow = true,\n directives = [],\n expectedFieldType,\n placeholder,\n className,\n editorProps,\n hideLegend = false,\n}: LiquidEditorProps) {\n const blockSeparator = multiline ? \"\\n\" : \"\";\n const supportsOutput = directives.includes(\"output\");\n const hasSecretsResolver = !!searchSecrets;\n const hasConstantsResolver = !!searchConstants;\n\n const secretSource = useAsyncRemoteSource<SecretSuggestion>({ search: searchSecrets });\n const constantSource = useAsyncRemoteSource<ConstantSuggestion>({ search: searchConstants });\n\n // Warm caches once per resolver identity so the empty-query open is hot.\n useEffect(() => {\n secretSource.prefetch();\n }, [secretSource.prefetch]);\n\n useEffect(() => {\n constantSource.prefetch();\n }, [constantSource.prefetch]);\n\n const [chipTarget, setChipTarget] = useState<ChipEditTarget | null>(null);\n\n const tagChipExtension = useMemo(\n () =>\n TagChipDecoration.configure({\n onChipClick: (hit: ChipHit, el: HTMLElement) => {\n setChipTarget({\n kind: hit.kind,\n raw: hit.raw,\n from: hit.from,\n to: hit.to,\n rect: el.getBoundingClientRect(),\n });\n },\n }),\n [],\n );\n\n const editor = useEditor({\n extensions: [\n StarterKit.configure({ hardBreak: !multiline ? false : undefined }),\n tagChipExtension,\n ],\n parseOptions: { preserveWhitespace: \"full\" },\n editorProps: {\n ...editorProps,\n attributes: {\n class: cn(\n \"pz:px-2.5 pz:py-1 pz:text-sm pz:outline-none pz:break-words\",\n multiline\n ? autoGrow\n ? \"pz:min-h-24 pz:max-h-96 pz:overflow-auto pz:whitespace-pre-wrap\"\n : \"pz:overflow-auto pz:whitespace-pre-wrap\"\n : \"pz:min-h-8\",\n className,\n ),\n ...(placeholder ? { \"data-placeholder\": placeholder } : {}),\n ...editorProps?.attributes,\n },\n handleKeyDown(view, event) {\n if (editorProps?.handleKeyDown?.(view, event)) return true;\n // Single-line: Enter must not split the document. Multi-line: let\n // StarterKit handle Enter so paragraphs and blocks behave normally.\n if (!multiline && event.key === \"Enter\") return true;\n return false;\n },\n },\n content: textToTiptapHTML(value || \"\", multiline),\n onUpdate({ editor }) {\n onChange(editor.getText({ blockSeparator }));\n },\n });\n\n // Sync the editor's document when `value` changes from outside (e.g.\n // form reset, programmatic setValue). `useEditor` only reads `content`\n // at mount; without this hook the visible UI drifts from form state.\n // The early-return short-circuits the loop that the editor's own\n // `onUpdate` would otherwise create.\n useEffect(() => {\n if (!editor) return;\n const current = editor.getText({ blockSeparator });\n if (current === (value ?? \"\")) return;\n editor.commands.setContent(textToTiptapHTML(value ?? \"\", multiline), {\n emitUpdate: false,\n });\n }, [editor, value, multiline, blockSeparator]);\n\n const insertField = useCallback((name: string) => `{{ ${name} }}`, []);\n\n // Tracks the current query in the open reference picker. Drives the\n // `liveItems` recomputation below — when the async sources resolve, we\n // re-render the picker against this query without waiting for Tiptap to\n // re-call items().\n const [referenceQuery, setReferenceQuery] = useState(\"\");\n\n // In sectioned (empty-query) view, cap each kind at SECTION_CAP visible\n // rows. Users see a compact summary and type to filter; the act of\n // filtering switches to flat mode where all matches are shown.\n // Caps are applied at this layer (not inside the picker) so the array\n // passed to SuggestionMenu matches what's rendered — keyboard nav\n // operates on the visible set and never lands on a hidden row.\n const buildVisibleItems = useCallback(\n (\n query: string,\n ): {\n items: SuggestionItem<ReferenceContext>[];\n overflow: Record<ReferenceContext[\"kind\"], number>;\n } => {\n const all = buildReferenceItems(\n query,\n {\n inputFields,\n secretSuggestions: secretSource.items,\n constantSuggestions: constantSource.items,\n },\n expectedFieldType,\n insertField,\n );\n const { prefix, residual } = parseQuery(query);\n const isFlat = !!residual.trim() || prefix !== null;\n if (isFlat) {\n return { items: all, overflow: { field: 0, secret: 0, constant: 0 } };\n }\n const fields = all.filter((i) => i.context?.kind === \"field\");\n const secrets = all.filter((i) => i.context?.kind === \"secret\");\n const constants = all.filter((i) => i.context?.kind === \"constant\");\n return {\n items: [\n ...fields.slice(0, SECTION_CAP),\n ...secrets.slice(0, SECTION_CAP),\n ...constants.slice(0, SECTION_CAP),\n ],\n overflow: {\n field: Math.max(0, fields.length - SECTION_CAP),\n secret: Math.max(0, secrets.length - SECTION_CAP),\n constant: Math.max(0, constants.length - SECTION_CAP),\n },\n };\n },\n [inputFields, expectedFieldType, insertField, secretSource.items, constantSource.items],\n );\n\n const referenceItems = useCallback(\n ({ query }: { query: string }): SuggestionItem<ReferenceContext>[] => {\n setReferenceQuery(query);\n // Fire-and-forget: results land via React state in `secretSource.items`\n // / `constantSource.items` and trigger a re-render. The popup reads\n // them through `liveItems` (see below).\n secretSource.ensure(query);\n constantSource.ensure(query);\n return buildVisibleItems(query).items;\n },\n [secretSource.ensure, constantSource.ensure, buildVisibleItems],\n );\n\n // Live items derived from the current query + cached source items. This is\n // recomputed whenever an async source resolves (which updates\n // `secretSource.items` / `constantSource.items` via setState). Passed to\n // SuggestionMenu via `liveItems` so the open popup re-renders without\n // needing the user to type — Tiptap's items() callback alone cannot\n // deliver async results that arrive between keystrokes.\n const { items: liveReferenceItems, overflow: liveOverflow } = useMemo(\n () => buildVisibleItems(referenceQuery),\n [referenceQuery, buildVisibleItems],\n );\n\n const directiveItems = useCallback(\n () =>\n RECORD_FIELD_TYPES.map<SuggestionItem>((fieldType) => ({\n title: `${fieldType}`,\n keywords: [fieldType, \"output\"],\n onSelect: ({ editor: ed, range }) => {\n ed.chain().focus().insertContentAt(range, OUTPUT_TEMPLATE(fieldType)).run();\n },\n })),\n [],\n );\n\n const legendEntries: LegendEntry[] = [];\n legendEntries.push({ key: \"/\", label: \"to insert a reference\" });\n if (supportsOutput) legendEntries.push({ key: \"@\", label: \"to add an output field\" });\n\n return (\n <EditorContext.Provider value={{ editor }}>\n <EditorContent editor={editor} />\n\n {!hideLegend && <FieldLegend entries={legendEntries} />}\n\n <SuggestionMenu\n editor={editor}\n char=\"/\"\n pluginKey=\"liquidEditorReferencePicker\"\n items={referenceItems}\n liveItems={liveReferenceItems}\n >\n {(props) => (\n <UnifiedReferencePicker\n items={props.items as SuggestionItem<ReferenceContext>[]}\n selectedIndex={props.selectedIndex}\n onSelect={props.onSelect as (item: SuggestionItem<ReferenceContext>) => void}\n query={props.query}\n hasSecretsResolver={hasSecretsResolver}\n hasConstantsResolver={hasConstantsResolver}\n inputFieldsCount={inputFields.length}\n secretsPending={secretSource.pending}\n constantsPending={constantSource.pending}\n overflow={liveOverflow}\n />\n )}\n </SuggestionMenu>\n\n {supportsOutput && (\n <SuggestionMenu\n editor={editor}\n char=\"@\"\n pluginKey=\"liquidEditorDirectivePicker\"\n items={directiveItems}\n >\n {({ items, selectedIndex, onSelect }) => (\n <div className=\"pz:flex pz:flex-col pz:gap-0.5 pz:p-1 pz:min-w-56\" role=\"listbox\">\n <div className=\"pz:px-2 pz:pt-1 pz:pb-0.5 pz:text-[10px] pz:font-medium pz:uppercase pz:tracking-wide pz:text-muted-foreground\">\n Add output declaration\n </div>\n {items.map((item, index) => (\n <button\n key={item.title}\n type=\"button\"\n role=\"option\"\n aria-selected={selectedIndex === index}\n onClick={() => onSelect(item)}\n className={cn(\n \"pz:flex pz:w-full pz:items-center pz:rounded-sm pz:px-2 pz:py-1.5 pz:text-sm pz:text-left pz:cursor-pointer\",\n selectedIndex === index\n ? \"pz:bg-accent pz:text-accent-foreground\"\n : \"pz:hover:bg-accent pz:hover:text-accent-foreground\",\n )}\n >\n {item.title}\n </button>\n ))}\n </div>\n )}\n </SuggestionMenu>\n )}\n\n {chipTarget && editor && (\n <ChipEditPopover editor={editor} target={chipTarget} onClose={() => setChipTarget(null)} />\n )}\n </EditorContext.Provider>\n );\n}\n"],"mappings":"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"}
@@ -1,3 +1,4 @@
1
+ import { useFormAlert } from "../../context/form-context.mjs";
1
2
  import { jsx, jsxs } from "react/jsx-runtime";
2
3
  import { useFormState } from "react-hook-form";
3
4
 
@@ -43,6 +44,7 @@ function collectErrors(errors, prefix = "") {
43
44
  */
44
45
  function FormLevelErrors({ control, fieldPaths }) {
45
46
  const { errors, isSubmitted } = useFormState({ control });
47
+ const Alert = useFormAlert();
46
48
  if (!isSubmitted) return null;
47
49
  const rootMessage = typeof errors?.root === "object" && errors.root && "message" in errors.root && typeof errors.root.message === "string" ? errors.root.message : void 0;
48
50
  const isOwnedByField = (path) => {
@@ -52,10 +54,9 @@ function FormLevelErrors({ control, fieldPaths }) {
52
54
  };
53
55
  const others = collectErrors(errors).filter((e) => !isOwnedByField(e.path));
54
56
  if (!rootMessage && others.length === 0) return null;
55
- return /* @__PURE__ */ jsxs("div", {
57
+ return /* @__PURE__ */ jsxs(Alert, {
58
+ variant: "error",
56
59
  "data-p0": "form-errors",
57
- role: "alert",
58
- className: "pz:flex pz:flex-col pz:gap-1 pz:rounded-md pz:border pz:border-destructive/50 pz:bg-destructive/5 pz:px-3 pz:py-2 pz:text-destructive pz:text-xs pz:font-medium",
59
60
  children: [rootMessage && /* @__PURE__ */ jsx("span", {
60
61
  "data-p0-error-path": "root",
61
62
  children: rootMessage
@@ -1 +1 @@
1
- {"version":3,"file":"form-level-errors.mjs","names":[],"sources":["../../../src/components/internal/form-level-errors.tsx"],"sourcesContent":["import { type Control, type FieldErrors, useFormState } from \"react-hook-form\";\n\ntype CollectedError = { path: string; message: string };\n\nfunction isFieldErrorNode(node: unknown): node is { message: string; type: string } {\n return (\n !!node &&\n typeof node === \"object\" &&\n typeof (node as { message?: unknown }).message === \"string\" &&\n typeof (node as { type?: unknown }).type === \"string\"\n );\n}\n\nconst FIELD_ERROR_KEYS = new Set([\"message\", \"type\", \"ref\", \"types\", \"root\"]);\n\nfunction collectErrors(\n errors: FieldErrors | Record<string, unknown> | undefined,\n prefix = \"\",\n): CollectedError[] {\n if (!errors || typeof errors !== \"object\") return [];\n const out: CollectedError[] = [];\n for (const key of Object.keys(errors)) {\n const node = (errors as Record<string, unknown>)[key];\n if (!node) continue;\n const path = prefix ? `${prefix}.${key}` : key;\n if (isFieldErrorNode(node)) {\n out.push({ path, message: node.message });\n }\n if (node && typeof node === \"object\") {\n const nested: Record<string, unknown> = {};\n for (const childKey of Object.keys(node as Record<string, unknown>)) {\n if (FIELD_ERROR_KEYS.has(childKey)) continue;\n nested[childKey] = (node as Record<string, unknown>)[childKey];\n }\n out.push(...collectErrors(nested, path));\n }\n }\n return out;\n}\n\n/**\n * Renders any errors set on the form that are not attached to a rendered\n * field. This surfaces:\n * - root errors (e.g. `errors.root`)\n * - container-level errors set on non-leaf paths (e.g. a Zod custom check\n * on `config.filters` that says \"You must set at least one filter.\")\n */\nexport function FormLevelErrors({\n control,\n fieldPaths,\n}: {\n control: Control<any>;\n fieldPaths: Set<string>;\n}) {\n const { errors, isSubmitted } = useFormState({ control });\n\n // Match `useFieldError`: only surface errors after the form has been\n // submitted at least once. Otherwise merely focusing a field triggers\n // live validation and makes the form feel immediately \"broken\".\n if (!isSubmitted) return null;\n\n const rootMessage =\n typeof errors?.root === \"object\" &&\n errors.root &&\n \"message\" in errors.root &&\n typeof (errors.root as { message?: unknown }).message === \"string\"\n ? (errors.root as { message: string }).message\n : undefined;\n\n // Errors on any rendered field — or on any descendant of a rendered field —\n // belong to that field's adapter, not the global banner. Complex adapters\n // like json_extraction / pipes_trigger register a single path at the top\n // level and render their own inline errors for nested paths underneath.\n const isOwnedByField = (path: string) => {\n if (fieldPaths.has(path)) return true;\n for (const p of fieldPaths) {\n if (path.startsWith(`${p}.`)) return true;\n }\n return false;\n };\n\n const others = collectErrors(errors).filter((e) => !isOwnedByField(e.path));\n\n if (!rootMessage && others.length === 0) return null;\n\n return (\n <div\n data-p0=\"form-errors\"\n role=\"alert\"\n className=\"pz:flex pz:flex-col pz:gap-1 pz:rounded-md pz:border pz:border-destructive/50 pz:bg-destructive/5 pz:px-3 pz:py-2 pz:text-destructive pz:text-xs pz:font-medium\"\n >\n {rootMessage && <span data-p0-error-path=\"root\">{rootMessage}</span>}\n {others.map((e) => (\n <span key={e.path} data-p0-error-path={e.path}>\n {e.message}\n </span>\n ))}\n </div>\n );\n}\n"],"mappings":";;;;AAIA,SAAS,iBAAiB,MAA0D;AAClF,QACE,CAAC,CAAC,QACF,OAAO,SAAS,YAChB,OAAQ,KAA+B,YAAY,YACnD,OAAQ,KAA4B,SAAS;;AAIjD,MAAM,mBAAmB,IAAI,IAAI;CAAC;CAAW;CAAQ;CAAO;CAAS;CAAO,CAAC;AAE7E,SAAS,cACP,QACA,SAAS,IACS;AAClB,KAAI,CAAC,UAAU,OAAO,WAAW,SAAU,QAAO,EAAE;CACpD,MAAM,MAAwB,EAAE;AAChC,MAAK,MAAM,OAAO,OAAO,KAAK,OAAO,EAAE;EACrC,MAAM,OAAQ,OAAmC;AACjD,MAAI,CAAC,KAAM;EACX,MAAM,OAAO,SAAS,GAAG,OAAO,GAAG,QAAQ;AAC3C,MAAI,iBAAiB,KAAK,CACxB,KAAI,KAAK;GAAE;GAAM,SAAS,KAAK;GAAS,CAAC;AAE3C,MAAI,QAAQ,OAAO,SAAS,UAAU;GACpC,MAAM,SAAkC,EAAE;AAC1C,QAAK,MAAM,YAAY,OAAO,KAAK,KAAgC,EAAE;AACnE,QAAI,iBAAiB,IAAI,SAAS,CAAE;AACpC,WAAO,YAAa,KAAiC;;AAEvD,OAAI,KAAK,GAAG,cAAc,QAAQ,KAAK,CAAC;;;AAG5C,QAAO;;;;;;;;;AAUT,SAAgB,gBAAgB,EAC9B,SACA,cAIC;CACD,MAAM,EAAE,QAAQ,gBAAgB,aAAa,EAAE,SAAS,CAAC;AAKzD,KAAI,CAAC,YAAa,QAAO;CAEzB,MAAM,cACJ,OAAO,QAAQ,SAAS,YACxB,OAAO,QACP,aAAa,OAAO,QACpB,OAAQ,OAAO,KAA+B,YAAY,WACrD,OAAO,KAA6B,UACrC;CAMN,MAAM,kBAAkB,SAAiB;AACvC,MAAI,WAAW,IAAI,KAAK,CAAE,QAAO;AACjC,OAAK,MAAM,KAAK,WACd,KAAI,KAAK,WAAW,GAAG,EAAE,GAAG,CAAE,QAAO;AAEvC,SAAO;;CAGT,MAAM,SAAS,cAAc,OAAO,CAAC,QAAQ,MAAM,CAAC,eAAe,EAAE,KAAK,CAAC;AAE3E,KAAI,CAAC,eAAe,OAAO,WAAW,EAAG,QAAO;AAEhD,QACE,qBAAC,OAAD;EACE,WAAQ;EACR,MAAK;EACL,WAAU;YAHZ,CAKG,eAAe,oBAAC,QAAD;GAAM,sBAAmB;aAAQ;GAAmB,GACnE,OAAO,KAAK,MACX,oBAAC,QAAD;GAAmB,sBAAoB,EAAE;aACtC,EAAE;GACE,EAFI,EAAE,KAEN,CACP,CACE"}
1
+ {"version":3,"file":"form-level-errors.mjs","names":[],"sources":["../../../src/components/internal/form-level-errors.tsx"],"sourcesContent":["import { type Control, type FieldErrors, useFormState } from \"react-hook-form\";\nimport { useFormAlert } from \"../../context/form-context.js\";\n\ntype CollectedError = { path: string; message: string };\n\nfunction isFieldErrorNode(node: unknown): node is { message: string; type: string } {\n return (\n !!node &&\n typeof node === \"object\" &&\n typeof (node as { message?: unknown }).message === \"string\" &&\n typeof (node as { type?: unknown }).type === \"string\"\n );\n}\n\nconst FIELD_ERROR_KEYS = new Set([\"message\", \"type\", \"ref\", \"types\", \"root\"]);\n\nfunction collectErrors(\n errors: FieldErrors | Record<string, unknown> | undefined,\n prefix = \"\",\n): CollectedError[] {\n if (!errors || typeof errors !== \"object\") return [];\n const out: CollectedError[] = [];\n for (const key of Object.keys(errors)) {\n const node = (errors as Record<string, unknown>)[key];\n if (!node) continue;\n const path = prefix ? `${prefix}.${key}` : key;\n if (isFieldErrorNode(node)) {\n out.push({ path, message: node.message });\n }\n if (node && typeof node === \"object\") {\n const nested: Record<string, unknown> = {};\n for (const childKey of Object.keys(node as Record<string, unknown>)) {\n if (FIELD_ERROR_KEYS.has(childKey)) continue;\n nested[childKey] = (node as Record<string, unknown>)[childKey];\n }\n out.push(...collectErrors(nested, path));\n }\n }\n return out;\n}\n\n/**\n * Renders any errors set on the form that are not attached to a rendered\n * field. This surfaces:\n * - root errors (e.g. `errors.root`)\n * - container-level errors set on non-leaf paths (e.g. a Zod custom check\n * on `config.filters` that says \"You must set at least one filter.\")\n */\nexport function FormLevelErrors({\n control,\n fieldPaths,\n}: {\n control: Control<any>;\n fieldPaths: Set<string>;\n}) {\n const { errors, isSubmitted } = useFormState({ control });\n const Alert = useFormAlert();\n\n // Match `useFieldError`: only surface errors after the form has been\n // submitted at least once. Otherwise merely focusing a field triggers\n // live validation and makes the form feel immediately \"broken\".\n if (!isSubmitted) return null;\n\n const rootMessage =\n typeof errors?.root === \"object\" &&\n errors.root &&\n \"message\" in errors.root &&\n typeof (errors.root as { message?: unknown }).message === \"string\"\n ? (errors.root as { message: string }).message\n : undefined;\n\n // Errors on any rendered field — or on any descendant of a rendered field —\n // belong to that field's adapter, not the global banner. Complex adapters\n // like json_extraction / pipes_trigger register a single path at the top\n // level and render their own inline errors for nested paths underneath.\n const isOwnedByField = (path: string) => {\n if (fieldPaths.has(path)) return true;\n for (const p of fieldPaths) {\n if (path.startsWith(`${p}.`)) return true;\n }\n return false;\n };\n\n const others = collectErrors(errors).filter((e) => !isOwnedByField(e.path));\n\n if (!rootMessage && others.length === 0) return null;\n\n return (\n <Alert variant=\"error\" data-p0=\"form-errors\">\n {rootMessage && <span data-p0-error-path=\"root\">{rootMessage}</span>}\n {others.map((e) => (\n <span key={e.path} data-p0-error-path={e.path}>\n {e.message}\n </span>\n ))}\n </Alert>\n );\n}\n"],"mappings":";;;;;AAKA,SAAS,iBAAiB,MAA0D;AAClF,QACE,CAAC,CAAC,QACF,OAAO,SAAS,YAChB,OAAQ,KAA+B,YAAY,YACnD,OAAQ,KAA4B,SAAS;;AAIjD,MAAM,mBAAmB,IAAI,IAAI;CAAC;CAAW;CAAQ;CAAO;CAAS;CAAO,CAAC;AAE7E,SAAS,cACP,QACA,SAAS,IACS;AAClB,KAAI,CAAC,UAAU,OAAO,WAAW,SAAU,QAAO,EAAE;CACpD,MAAM,MAAwB,EAAE;AAChC,MAAK,MAAM,OAAO,OAAO,KAAK,OAAO,EAAE;EACrC,MAAM,OAAQ,OAAmC;AACjD,MAAI,CAAC,KAAM;EACX,MAAM,OAAO,SAAS,GAAG,OAAO,GAAG,QAAQ;AAC3C,MAAI,iBAAiB,KAAK,CACxB,KAAI,KAAK;GAAE;GAAM,SAAS,KAAK;GAAS,CAAC;AAE3C,MAAI,QAAQ,OAAO,SAAS,UAAU;GACpC,MAAM,SAAkC,EAAE;AAC1C,QAAK,MAAM,YAAY,OAAO,KAAK,KAAgC,EAAE;AACnE,QAAI,iBAAiB,IAAI,SAAS,CAAE;AACpC,WAAO,YAAa,KAAiC;;AAEvD,OAAI,KAAK,GAAG,cAAc,QAAQ,KAAK,CAAC;;;AAG5C,QAAO;;;;;;;;;AAUT,SAAgB,gBAAgB,EAC9B,SACA,cAIC;CACD,MAAM,EAAE,QAAQ,gBAAgB,aAAa,EAAE,SAAS,CAAC;CACzD,MAAM,QAAQ,cAAc;AAK5B,KAAI,CAAC,YAAa,QAAO;CAEzB,MAAM,cACJ,OAAO,QAAQ,SAAS,YACxB,OAAO,QACP,aAAa,OAAO,QACpB,OAAQ,OAAO,KAA+B,YAAY,WACrD,OAAO,KAA6B,UACrC;CAMN,MAAM,kBAAkB,SAAiB;AACvC,MAAI,WAAW,IAAI,KAAK,CAAE,QAAO;AACjC,OAAK,MAAM,KAAK,WACd,KAAI,KAAK,WAAW,GAAG,EAAE,GAAG,CAAE,QAAO;AAEvC,SAAO;;CAGT,MAAM,SAAS,cAAc,OAAO,CAAC,QAAQ,MAAM,CAAC,eAAe,EAAE,KAAK,CAAC;AAE3E,KAAI,CAAC,eAAe,OAAO,WAAW,EAAG,QAAO;AAEhD,QACE,qBAAC,OAAD;EAAO,SAAQ;EAAQ,WAAQ;YAA/B,CACG,eAAe,oBAAC,QAAD;GAAM,sBAAmB;aAAQ;GAAmB,GACnE,OAAO,KAAK,MACX,oBAAC,QAAD;GAAmB,sBAAoB,EAAE;aACtC,EAAE;GACE,EAFI,EAAE,KAEN,CACP,CACI"}
@@ -41,6 +41,32 @@ function IconInfo(props) {
41
41
  ]
42
42
  });
43
43
  }
44
+ function IconWarning(props) {
45
+ return /* @__PURE__ */ jsxs("svg", {
46
+ ...defaults,
47
+ ...props,
48
+ children: [
49
+ /* @__PURE__ */ jsx("path", { d: "m21.73 18-8-14a2 2 0 0 0-3.48 0l-8 14A2 2 0 0 0 4 21h16a2 2 0 0 0 1.73-3" }),
50
+ /* @__PURE__ */ jsx("path", { d: "M12 9v4" }),
51
+ /* @__PURE__ */ jsx("path", { d: "M12 17h.01" })
52
+ ]
53
+ });
54
+ }
55
+ function IconError(props) {
56
+ return /* @__PURE__ */ jsxs("svg", {
57
+ ...defaults,
58
+ ...props,
59
+ children: [
60
+ /* @__PURE__ */ jsx("circle", {
61
+ cx: "12",
62
+ cy: "12",
63
+ r: "10"
64
+ }),
65
+ /* @__PURE__ */ jsx("path", { d: "m15 9-6 6" }),
66
+ /* @__PURE__ */ jsx("path", { d: "m9 9 6 6" })
67
+ ]
68
+ });
69
+ }
44
70
  function IconPencil(props) {
45
71
  return /* @__PURE__ */ jsx("svg", {
46
72
  ...defaults,
@@ -162,5 +188,5 @@ function IconRefresh(props) {
162
188
  }
163
189
 
164
190
  //#endregion
165
- export { IconCheck, IconChevronDown, IconEye, IconEyeOff, IconGripVertical, IconInfo, IconLock, IconMinus, IconPencil, IconPlus, IconRefresh, IconTrash };
191
+ export { IconCheck, IconChevronDown, IconError, IconEye, IconEyeOff, IconGripVertical, IconInfo, IconLock, IconMinus, IconPencil, IconPlus, IconRefresh, IconTrash, IconWarning };
166
192
  //# sourceMappingURL=icons.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"icons.mjs","names":[],"sources":["../../../src/components/internal/icons.tsx"],"sourcesContent":["import type { SVGProps } from \"react\";\n\ntype IconProps = SVGProps<SVGSVGElement>;\n\nconst defaults: IconProps = {\n xmlns: \"http://www.w3.org/2000/svg\",\n width: 16,\n height: 16,\n viewBox: \"0 0 24 24\",\n fill: \"none\",\n stroke: \"currentColor\",\n strokeWidth: 2,\n strokeLinecap: \"round\" as const,\n strokeLinejoin: \"round\" as const,\n};\n\nexport function IconPlus(props: IconProps) {\n return (\n <svg {...defaults} {...props}>\n <path d=\"M5 12h14\" />\n <path d=\"M12 5v14\" />\n </svg>\n );\n}\n\nexport function IconMinus(props: IconProps) {\n return (\n <svg {...defaults} {...props}>\n <path d=\"M5 12h14\" />\n </svg>\n );\n}\n\nexport function IconX(props: IconProps) {\n return (\n <svg {...defaults} {...props}>\n <path d=\"M18 6 6 18\" />\n <path d=\"m6 6 12 12\" />\n </svg>\n );\n}\n\nexport function IconInfo(props: IconProps) {\n return (\n <svg {...defaults} {...props}>\n <circle cx=\"12\" cy=\"12\" r=\"10\" />\n <path d=\"M12 16v-4\" />\n <path d=\"M12 8h.01\" />\n </svg>\n );\n}\n\nexport function IconPencil(props: IconProps) {\n return (\n <svg {...defaults} {...props}>\n <path d=\"M21.174 6.812a1 1 0 0 0-3.986-3.987L3.842 16.174a2 2 0 0 0-.5.83l-1.321 4.352a.5.5 0 0 0 .623.622l4.353-1.32a2 2 0 0 0 .83-.497z\" />\n </svg>\n );\n}\n\nexport function IconTrash(props: IconProps) {\n return (\n <svg {...defaults} {...props}>\n <path d=\"M3 6h18\" />\n <path d=\"M19 6v14c0 1-1 2-2 2H7c-1 0-2-1-2-2V6\" />\n <path d=\"M8 6V4c0-1 1-2 2-2h4c1 0 2 1 2 2v2\" />\n </svg>\n );\n}\n\nexport function IconChevronDown(props: IconProps) {\n return (\n <svg {...defaults} {...props}>\n <path d=\"m6 9 6 6 6-6\" />\n </svg>\n );\n}\n\nexport function IconLock(props: IconProps) {\n return (\n <svg {...defaults} {...props}>\n <rect width=\"18\" height=\"11\" x=\"3\" y=\"11\" rx=\"2\" ry=\"2\" />\n <path d=\"M7 11V7a5 5 0 0 1 10 0v4\" />\n </svg>\n );\n}\n\nexport function IconGripVertical(props: IconProps) {\n return (\n <svg {...defaults} {...props}>\n <circle cx=\"9\" cy=\"12\" r=\"1\" />\n <circle cx=\"9\" cy=\"5\" r=\"1\" />\n <circle cx=\"9\" cy=\"19\" r=\"1\" />\n <circle cx=\"15\" cy=\"12\" r=\"1\" />\n <circle cx=\"15\" cy=\"5\" r=\"1\" />\n <circle cx=\"15\" cy=\"19\" r=\"1\" />\n </svg>\n );\n}\n\nexport function IconMoreHorizontal(props: IconProps) {\n return (\n <svg {...defaults} {...props}>\n <circle cx=\"12\" cy=\"12\" r=\"1\" />\n <circle cx=\"19\" cy=\"12\" r=\"1\" />\n <circle cx=\"5\" cy=\"12\" r=\"1\" />\n </svg>\n );\n}\n\nexport function IconPlay(props: IconProps) {\n return (\n <svg {...defaults} {...props}>\n <polygon points=\"6 3 20 12 6 21 6 3\" fill=\"currentColor\" />\n </svg>\n );\n}\n\nexport function IconCheck(props: IconProps) {\n return (\n <svg {...defaults} {...props}>\n <path d=\"M20 6 9 17l-5-5\" />\n </svg>\n );\n}\n\nexport function IconChevronRight(props: IconProps) {\n return (\n <svg {...defaults} {...props}>\n <path d=\"m9 18 6-6-6-6\" />\n </svg>\n );\n}\n\nexport function IconEye(props: IconProps) {\n return (\n <svg {...defaults} {...props}>\n <path d=\"M2.062 12.348a1 1 0 0 1 0-.696 10.75 10.75 0 0 1 19.876 0 1 1 0 0 1 0 .696 10.75 10.75 0 0 1-19.876 0\" />\n <circle cx=\"12\" cy=\"12\" r=\"3\" />\n </svg>\n );\n}\n\nexport function IconEyeOff(props: IconProps) {\n return (\n <svg {...defaults} {...props}>\n <path d=\"M10.733 5.076a10.744 10.744 0 0 1 11.205 6.575 1 1 0 0 1 0 .696 10.747 10.747 0 0 1-1.444 2.49\" />\n <path d=\"M14.084 14.158a3 3 0 0 1-4.242-4.242\" />\n <path d=\"M17.479 17.499a10.75 10.75 0 0 1-15.417-5.151 1 1 0 0 1 0-.696 10.75 10.75 0 0 1 4.446-5.143\" />\n <path d=\"m2 2 20 20\" />\n </svg>\n );\n}\n\nexport function IconRefresh(props: IconProps) {\n return (\n <svg {...defaults} {...props}>\n <path d=\"M3 12a9 9 0 0 1 9-9 9.75 9.75 0 0 1 6.74 2.74L21 8\" />\n <path d=\"M21 3v5h-5\" />\n <path d=\"M21 12a9 9 0 0 1-9 9 9.75 9.75 0 0 1-6.74-2.74L3 16\" />\n <path d=\"M8 16H3v5\" />\n </svg>\n );\n}\n\nexport function IconBraces(props: IconProps) {\n return (\n <svg {...defaults} {...props}>\n <path d=\"M8 3H7a2 2 0 0 0-2 2v5a2 2 0 0 1-2 2 2 2 0 0 1 2 2v5a2 2 0 0 0 2 2h1\" />\n <path d=\"M16 21h1a2 2 0 0 0 2-2v-5a2 2 0 0 1 2-2 2 2 0 0 1-2-2V5a2 2 0 0 0-2-2h-1\" />\n </svg>\n );\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"icons.mjs","names":[],"sources":["../../../src/components/internal/icons.tsx"],"sourcesContent":["import type { SVGProps } from \"react\";\n\ntype IconProps = SVGProps<SVGSVGElement>;\n\nconst defaults: IconProps = {\n xmlns: \"http://www.w3.org/2000/svg\",\n width: 16,\n height: 16,\n viewBox: \"0 0 24 24\",\n fill: \"none\",\n stroke: \"currentColor\",\n strokeWidth: 2,\n strokeLinecap: \"round\" as const,\n strokeLinejoin: \"round\" as const,\n};\n\nexport function IconPlus(props: IconProps) {\n return (\n <svg {...defaults} {...props}>\n <path d=\"M5 12h14\" />\n <path d=\"M12 5v14\" />\n </svg>\n );\n}\n\nexport function IconMinus(props: IconProps) {\n return (\n <svg {...defaults} {...props}>\n <path d=\"M5 12h14\" />\n </svg>\n );\n}\n\nexport function IconX(props: IconProps) {\n return (\n <svg {...defaults} {...props}>\n <path d=\"M18 6 6 18\" />\n <path d=\"m6 6 12 12\" />\n </svg>\n );\n}\n\nexport function IconInfo(props: IconProps) {\n return (\n <svg {...defaults} {...props}>\n <circle cx=\"12\" cy=\"12\" r=\"10\" />\n <path d=\"M12 16v-4\" />\n <path d=\"M12 8h.01\" />\n </svg>\n );\n}\n\nexport function IconWarning(props: IconProps) {\n return (\n <svg {...defaults} {...props}>\n <path d=\"m21.73 18-8-14a2 2 0 0 0-3.48 0l-8 14A2 2 0 0 0 4 21h16a2 2 0 0 0 1.73-3\" />\n <path d=\"M12 9v4\" />\n <path d=\"M12 17h.01\" />\n </svg>\n );\n}\n\nexport function IconError(props: IconProps) {\n return (\n <svg {...defaults} {...props}>\n <circle cx=\"12\" cy=\"12\" r=\"10\" />\n <path d=\"m15 9-6 6\" />\n <path d=\"m9 9 6 6\" />\n </svg>\n );\n}\n\nexport function IconPencil(props: IconProps) {\n return (\n <svg {...defaults} {...props}>\n <path d=\"M21.174 6.812a1 1 0 0 0-3.986-3.987L3.842 16.174a2 2 0 0 0-.5.83l-1.321 4.352a.5.5 0 0 0 .623.622l4.353-1.32a2 2 0 0 0 .83-.497z\" />\n </svg>\n );\n}\n\nexport function IconTrash(props: IconProps) {\n return (\n <svg {...defaults} {...props}>\n <path d=\"M3 6h18\" />\n <path d=\"M19 6v14c0 1-1 2-2 2H7c-1 0-2-1-2-2V6\" />\n <path d=\"M8 6V4c0-1 1-2 2-2h4c1 0 2 1 2 2v2\" />\n </svg>\n );\n}\n\nexport function IconChevronDown(props: IconProps) {\n return (\n <svg {...defaults} {...props}>\n <path d=\"m6 9 6 6 6-6\" />\n </svg>\n );\n}\n\nexport function IconLock(props: IconProps) {\n return (\n <svg {...defaults} {...props}>\n <rect width=\"18\" height=\"11\" x=\"3\" y=\"11\" rx=\"2\" ry=\"2\" />\n <path d=\"M7 11V7a5 5 0 0 1 10 0v4\" />\n </svg>\n );\n}\n\nexport function IconGripVertical(props: IconProps) {\n return (\n <svg {...defaults} {...props}>\n <circle cx=\"9\" cy=\"12\" r=\"1\" />\n <circle cx=\"9\" cy=\"5\" r=\"1\" />\n <circle cx=\"9\" cy=\"19\" r=\"1\" />\n <circle cx=\"15\" cy=\"12\" r=\"1\" />\n <circle cx=\"15\" cy=\"5\" r=\"1\" />\n <circle cx=\"15\" cy=\"19\" r=\"1\" />\n </svg>\n );\n}\n\nexport function IconMoreHorizontal(props: IconProps) {\n return (\n <svg {...defaults} {...props}>\n <circle cx=\"12\" cy=\"12\" r=\"1\" />\n <circle cx=\"19\" cy=\"12\" r=\"1\" />\n <circle cx=\"5\" cy=\"12\" r=\"1\" />\n </svg>\n );\n}\n\nexport function IconPlay(props: IconProps) {\n return (\n <svg {...defaults} {...props}>\n <polygon points=\"6 3 20 12 6 21 6 3\" fill=\"currentColor\" />\n </svg>\n );\n}\n\nexport function IconCheck(props: IconProps) {\n return (\n <svg {...defaults} {...props}>\n <path d=\"M20 6 9 17l-5-5\" />\n </svg>\n );\n}\n\nexport function IconChevronRight(props: IconProps) {\n return (\n <svg {...defaults} {...props}>\n <path d=\"m9 18 6-6-6-6\" />\n </svg>\n );\n}\n\nexport function IconEye(props: IconProps) {\n return (\n <svg {...defaults} {...props}>\n <path d=\"M2.062 12.348a1 1 0 0 1 0-.696 10.75 10.75 0 0 1 19.876 0 1 1 0 0 1 0 .696 10.75 10.75 0 0 1-19.876 0\" />\n <circle cx=\"12\" cy=\"12\" r=\"3\" />\n </svg>\n );\n}\n\nexport function IconEyeOff(props: IconProps) {\n return (\n <svg {...defaults} {...props}>\n <path d=\"M10.733 5.076a10.744 10.744 0 0 1 11.205 6.575 1 1 0 0 1 0 .696 10.747 10.747 0 0 1-1.444 2.49\" />\n <path d=\"M14.084 14.158a3 3 0 0 1-4.242-4.242\" />\n <path d=\"M17.479 17.499a10.75 10.75 0 0 1-15.417-5.151 1 1 0 0 1 0-.696 10.75 10.75 0 0 1 4.446-5.143\" />\n <path d=\"m2 2 20 20\" />\n </svg>\n );\n}\n\nexport function IconRefresh(props: IconProps) {\n return (\n <svg {...defaults} {...props}>\n <path d=\"M3 12a9 9 0 0 1 9-9 9.75 9.75 0 0 1 6.74 2.74L21 8\" />\n <path d=\"M21 3v5h-5\" />\n <path d=\"M21 12a9 9 0 0 1-9 9 9.75 9.75 0 0 1-6.74-2.74L3 16\" />\n <path d=\"M8 16H3v5\" />\n </svg>\n );\n}\n\nexport function IconBraces(props: IconProps) {\n return (\n <svg {...defaults} {...props}>\n <path d=\"M8 3H7a2 2 0 0 0-2 2v5a2 2 0 0 1-2 2 2 2 0 0 1 2 2v5a2 2 0 0 0 2 2h1\" />\n <path d=\"M16 21h1a2 2 0 0 0 2-2v-5a2 2 0 0 1 2-2 2 2 0 0 1-2-2V5a2 2 0 0 0-2-2h-1\" />\n </svg>\n );\n}\n"],"mappings":"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"}
@@ -0,0 +1,47 @@
1
+ import { ComponentProps } from "react";
2
+ import * as _$react_jsx_runtime0 from "react/jsx-runtime";
3
+ import { VariantProps } from "class-variance-authority";
4
+ import * as _$class_variance_authority_types0 from "class-variance-authority/types";
5
+
6
+ //#region src/components/ui/alert.d.ts
7
+ /**
8
+ * Notice box used across the form library (a field's disabled-reason, form-level
9
+ * validation / loader errors, …). Severity drives the left accent bar + icon
10
+ * colour. Children render in the body column with muted "description" styling by
11
+ * default; wrap a heading in {@link AlertTitle} for the bold title + muted body
12
+ * layout.
13
+ *
14
+ * The whole component is overridable per form via
15
+ * `<FormProvider components={{ alert: MyAlert }}>` — see `FormComponents`. The
16
+ * override receives `variant` + `children`, so one component can style every
17
+ * severity.
18
+ */
19
+ declare const alertVariants: (props?: ({
20
+ variant?: "info" | "error" | "warning" | null | undefined;
21
+ } & _$class_variance_authority_types0.ClassProp) | undefined) => string;
22
+ type AlertVariant = NonNullable<VariantProps<typeof alertVariants>["variant"]>;
23
+ interface AlertProps extends Omit<ComponentProps<"div">, "title"> {
24
+ variant?: AlertVariant;
25
+ /** Set `false` to hide the leading severity icon. */
26
+ icon?: boolean;
27
+ }
28
+ declare function Alert({
29
+ variant,
30
+ icon,
31
+ className,
32
+ children,
33
+ ...props
34
+ }: AlertProps): _$react_jsx_runtime0.JSX.Element;
35
+ /** Bold, foreground-coloured heading line inside an {@link Alert}. */
36
+ declare function AlertTitle({
37
+ className,
38
+ ...props
39
+ }: ComponentProps<"div">): _$react_jsx_runtime0.JSX.Element;
40
+ /** Muted body text inside an {@link Alert} (the default child styling). */
41
+ declare function AlertDescription({
42
+ className,
43
+ ...props
44
+ }: ComponentProps<"div">): _$react_jsx_runtime0.JSX.Element;
45
+ //#endregion
46
+ export { Alert, AlertDescription, AlertProps, AlertTitle, AlertVariant, alertVariants };
47
+ //# sourceMappingURL=alert.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"alert.d.mts","names":[],"sources":["../../../src/components/ui/alert.tsx"],"mappings":";;;;;;;;;;AAC4C;;;;;;;;cAgBtC,aAAA,GAAa,KAAA;;IAYlB,iCAAA,CAAA,SAAA;AAAA,KAIW,YAAA,GAAe,WAAA,CAAY,YAAA,QAAoB,aAAA;AAAA,UAE1C,UAAA,SAAmB,IAAA,CAAK,cAAA;EACvC,OAAA,GAAU,YAAA;EAHe;EAKzB,IAAA;AAAA;AAAA,iBAGc,KAAA,CAAA;EACd,OAAA;EACA,IAAA;EACA,SAAA;EACA,QAAA;EAAA,GACG;AAAA,GACF,UAAA,GAAU,oBAAA,CAAA,GAAA,CAAA,OAAA;;iBAsBG,UAAA,CAAA;EAAa,SAAA;EAAA,GAAc;AAAA,GAAS,cAAA,UAAqB,oBAAA,CAAA,GAAA,CAAA,OAAA;;iBAWzD,gBAAA,CAAA;EAAmB,SAAA;EAAA,GAAc;AAAA,GAAS,cAAA,UAAqB,oBAAA,CAAA,GAAA,CAAA,OAAA"}
@@ -0,0 +1,66 @@
1
+ import { cn } from "../../lib/utils.mjs";
2
+ import { IconError, IconInfo, IconWarning } from "../internal/icons.mjs";
3
+ import { jsx, jsxs } from "react/jsx-runtime";
4
+ import { cva } from "class-variance-authority";
5
+
6
+ //#region src/components/ui/alert.tsx
7
+ /**
8
+ * Notice box used across the form library (a field's disabled-reason, form-level
9
+ * validation / loader errors, …). Severity drives the left accent bar + icon
10
+ * colour. Children render in the body column with muted "description" styling by
11
+ * default; wrap a heading in {@link AlertTitle} for the bold title + muted body
12
+ * layout.
13
+ *
14
+ * The whole component is overridable per form via
15
+ * `<FormProvider components={{ alert: MyAlert }}>` — see `FormComponents`. The
16
+ * override receives `variant` + `children`, so one component can style every
17
+ * severity.
18
+ */
19
+ const alertVariants = cva("pz:group/alert pz:relative pz:flex pz:w-full pz:items-start pz:gap-2 pz:rounded-lg pz:border pz:bg-card pz:py-2.5 pz:pr-3 pz:pl-5 pz:text-left pz:text-sm pz:before:absolute pz:before:inset-y-2.5 pz:before:left-2 pz:before:w-0.5 pz:before:rounded-full pz:[&>svg]:size-4 pz:[&>svg]:shrink-0 pz:[&>svg]:translate-y-px", {
20
+ variants: { variant: {
21
+ info: "pz:before:bg-blue-500 pz:[&>svg]:text-blue-500",
22
+ warning: "pz:before:bg-amber-500 pz:[&>svg]:text-amber-500",
23
+ error: "pz:before:bg-destructive pz:[&>svg]:text-destructive"
24
+ } },
25
+ defaultVariants: { variant: "info" }
26
+ });
27
+ const VARIANT_ICON = {
28
+ info: IconInfo,
29
+ warning: IconWarning,
30
+ error: IconError
31
+ };
32
+ function Alert({ variant = "info", icon = true, className, children, ...props }) {
33
+ const Icon = VARIANT_ICON[variant];
34
+ return /* @__PURE__ */ jsxs("div", {
35
+ "data-slot": "alert",
36
+ "data-p0": "alert",
37
+ role: "alert",
38
+ className: cn(alertVariants({ variant }), className),
39
+ ...props,
40
+ children: [icon && /* @__PURE__ */ jsx(Icon, { "aria-hidden": "true" }), /* @__PURE__ */ jsx("div", {
41
+ "data-slot": "alert-body",
42
+ className: "pz:flex pz:min-w-0 pz:flex-col pz:gap-0.5 pz:text-muted-foreground pz:text-xs",
43
+ children
44
+ })]
45
+ });
46
+ }
47
+ /** Bold, foreground-coloured heading line inside an {@link Alert}. */
48
+ function AlertTitle({ className, ...props }) {
49
+ return /* @__PURE__ */ jsx("div", {
50
+ "data-slot": "alert-title",
51
+ className: cn("pz:font-medium pz:text-foreground pz:text-sm pz:leading-tight", className),
52
+ ...props
53
+ });
54
+ }
55
+ /** Muted body text inside an {@link Alert} (the default child styling). */
56
+ function AlertDescription({ className, ...props }) {
57
+ return /* @__PURE__ */ jsx("div", {
58
+ "data-slot": "alert-description",
59
+ className: cn("pz:flex pz:flex-col pz:gap-1 pz:text-muted-foreground pz:text-xs", className),
60
+ ...props
61
+ });
62
+ }
63
+
64
+ //#endregion
65
+ export { Alert, AlertDescription, AlertTitle, alertVariants };
66
+ //# sourceMappingURL=alert.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"alert.mjs","names":[],"sources":["../../../src/components/ui/alert.tsx"],"sourcesContent":["import { cva, type VariantProps } from \"class-variance-authority\";\nimport type { ComponentProps } from \"react\";\nimport { cn } from \"../../lib/utils.js\";\nimport { IconError, IconInfo, IconWarning } from \"../internal/icons.js\";\n\n/**\n * Notice box used across the form library (a field's disabled-reason, form-level\n * validation / loader errors, …). Severity drives the left accent bar + icon\n * colour. Children render in the body column with muted \"description\" styling by\n * default; wrap a heading in {@link AlertTitle} for the bold title + muted body\n * layout.\n *\n * The whole component is overridable per form via\n * `<FormProvider components={{ alert: MyAlert }}>` — see `FormComponents`. The\n * override receives `variant` + `children`, so one component can style every\n * severity.\n */\nconst alertVariants = cva(\n \"pz:group/alert pz:relative pz:flex pz:w-full pz:items-start pz:gap-2 pz:rounded-lg pz:border pz:bg-card pz:py-2.5 pz:pr-3 pz:pl-5 pz:text-left pz:text-sm pz:before:absolute pz:before:inset-y-2.5 pz:before:left-2 pz:before:w-0.5 pz:before:rounded-full pz:[&>svg]:size-4 pz:[&>svg]:shrink-0 pz:[&>svg]:translate-y-px\",\n {\n variants: {\n variant: {\n info: \"pz:before:bg-blue-500 pz:[&>svg]:text-blue-500\",\n warning: \"pz:before:bg-amber-500 pz:[&>svg]:text-amber-500\",\n error: \"pz:before:bg-destructive pz:[&>svg]:text-destructive\",\n },\n },\n defaultVariants: { variant: \"info\" },\n },\n);\n\nconst VARIANT_ICON = { info: IconInfo, warning: IconWarning, error: IconError } as const;\n\nexport type AlertVariant = NonNullable<VariantProps<typeof alertVariants>[\"variant\"]>;\n\nexport interface AlertProps extends Omit<ComponentProps<\"div\">, \"title\"> {\n variant?: AlertVariant;\n /** Set `false` to hide the leading severity icon. */\n icon?: boolean;\n}\n\nexport function Alert({\n variant = \"info\",\n icon = true,\n className,\n children,\n ...props\n}: AlertProps) {\n const Icon = VARIANT_ICON[variant];\n return (\n <div\n data-slot=\"alert\"\n data-p0=\"alert\"\n role=\"alert\"\n className={cn(alertVariants({ variant }), className)}\n {...props}\n >\n {icon && <Icon aria-hidden=\"true\" />}\n <div\n data-slot=\"alert-body\"\n className=\"pz:flex pz:min-w-0 pz:flex-col pz:gap-0.5 pz:text-muted-foreground pz:text-xs\"\n >\n {children}\n </div>\n </div>\n );\n}\n\n/** Bold, foreground-coloured heading line inside an {@link Alert}. */\nexport function AlertTitle({ className, ...props }: ComponentProps<\"div\">) {\n return (\n <div\n data-slot=\"alert-title\"\n className={cn(\"pz:font-medium pz:text-foreground pz:text-sm pz:leading-tight\", className)}\n {...props}\n />\n );\n}\n\n/** Muted body text inside an {@link Alert} (the default child styling). */\nexport function AlertDescription({ className, ...props }: ComponentProps<\"div\">) {\n return (\n <div\n data-slot=\"alert-description\"\n className={cn(\"pz:flex pz:flex-col pz:gap-1 pz:text-muted-foreground pz:text-xs\", className)}\n {...props}\n />\n );\n}\n\nexport { alertVariants };\n"],"mappings":";;;;;;;;;;;;;;;;;;AAiBA,MAAM,gBAAgB,IACpB,8TACA;CACE,UAAU,EACR,SAAS;EACP,MAAM;EACN,SAAS;EACT,OAAO;EACR,EACF;CACD,iBAAiB,EAAE,SAAS,QAAQ;CACrC,CACF;AAED,MAAM,eAAe;CAAE,MAAM;CAAU,SAAS;CAAa,OAAO;CAAW;AAU/E,SAAgB,MAAM,EACpB,UAAU,QACV,OAAO,MACP,WACA,UACA,GAAG,SACU;CACb,MAAM,OAAO,aAAa;AAC1B,QACE,qBAAC,OAAD;EACE,aAAU;EACV,WAAQ;EACR,MAAK;EACL,WAAW,GAAG,cAAc,EAAE,SAAS,CAAC,EAAE,UAAU;EACpD,GAAI;YALN,CAOG,QAAQ,oBAAC,MAAD,EAAM,eAAY,QAAS,GACpC,oBAAC,OAAD;GACE,aAAU;GACV,WAAU;GAET;GACG,EACF;;;;AAKV,SAAgB,WAAW,EAAE,WAAW,GAAG,SAAgC;AACzE,QACE,oBAAC,OAAD;EACE,aAAU;EACV,WAAW,GAAG,iEAAiE,UAAU;EACzF,GAAI;EACJ;;;AAKN,SAAgB,iBAAiB,EAAE,WAAW,GAAG,SAAgC;AAC/E,QACE,oBAAC,OAAD;EACE,aAAU;EACV,WAAW,GAAG,oEAAoE,UAAU;EAC5F,GAAI;EACJ"}
@@ -0,0 +1,21 @@
1
+ import { AlertProps } from "../components/ui/alert.mjs";
2
+ import { FieldAdapterMap, FormClassNames, FormComponents } from "../types/adapters.mjs";
3
+ import { ComponentType } from "react";
4
+
5
+ //#region src/context/form-context.d.ts
6
+ interface FormConfig {
7
+ adapters?: FieldAdapterMap;
8
+ classNames?: FormClassNames;
9
+ components?: FormComponents;
10
+ }
11
+ declare function useFormConfig(): FormConfig;
12
+ /**
13
+ * The Alert component the form chrome should render — the consumer's override
14
+ * from `<FormProvider components={{ alert }}>` if present, else the library
15
+ * default. Use this everywhere instead of importing `Alert` directly so notices
16
+ * stay customizable.
17
+ */
18
+ declare function useFormAlert(): ComponentType<AlertProps>;
19
+ //#endregion
20
+ export { FormConfig, useFormAlert, useFormConfig };
21
+ //# sourceMappingURL=form-context.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"form-context.d.mts","names":[],"sources":["../../src/context/form-context.ts"],"mappings":";;;;;UAIiB,UAAA;EACf,QAAA,GAAW,eAAA;EACX,UAAA,GAAa,cAAA;EACb,UAAA,GAAa,cAAA;AAAA;AAAA,iBAKC,aAAA,CAAA,GAAiB,UAAA;;;;;;;iBAUjB,YAAA,CAAA,GAAgB,aAAA,CAAc,UAAA"}
@@ -1,3 +1,4 @@
1
+ import { Alert } from "../components/ui/alert.mjs";
1
2
  import { createContext, useContext } from "react";
2
3
 
3
4
  //#region src/context/form-context.ts
@@ -5,7 +6,16 @@ const FormConfigContext = createContext({});
5
6
  function useFormConfig() {
6
7
  return useContext(FormConfigContext);
7
8
  }
9
+ /**
10
+ * The Alert component the form chrome should render — the consumer's override
11
+ * from `<FormProvider components={{ alert }}>` if present, else the library
12
+ * default. Use this everywhere instead of importing `Alert` directly so notices
13
+ * stay customizable.
14
+ */
15
+ function useFormAlert() {
16
+ return useFormConfig().components?.alert ?? Alert;
17
+ }
8
18
 
9
19
  //#endregion
10
- export { FormConfigContext, useFormConfig };
20
+ export { FormConfigContext, useFormAlert, useFormConfig };
11
21
  //# sourceMappingURL=form-context.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"form-context.mjs","names":[],"sources":["../../src/context/form-context.ts"],"sourcesContent":["import { createContext, useContext } from \"react\";\nimport type { FieldAdapterMap, FormClassNames } from \"../types/adapters.js\";\n\nexport interface FormConfig {\n adapters?: FieldAdapterMap;\n classNames?: FormClassNames;\n}\n\nexport const FormConfigContext = createContext<FormConfig>({});\n\nexport function useFormConfig(): FormConfig {\n return useContext(FormConfigContext);\n}\n"],"mappings":";;;AAQA,MAAa,oBAAoB,cAA0B,EAAE,CAAC;AAE9D,SAAgB,gBAA4B;AAC1C,QAAO,WAAW,kBAAkB"}
1
+ {"version":3,"file":"form-context.mjs","names":[],"sources":["../../src/context/form-context.ts"],"sourcesContent":["import { type ComponentType, createContext, useContext } from \"react\";\nimport { Alert, type AlertProps } from \"../components/ui/alert.js\";\nimport type { FieldAdapterMap, FormClassNames, FormComponents } from \"../types/adapters.js\";\n\nexport interface FormConfig {\n adapters?: FieldAdapterMap;\n classNames?: FormClassNames;\n components?: FormComponents;\n}\n\nexport const FormConfigContext = createContext<FormConfig>({});\n\nexport function useFormConfig(): FormConfig {\n return useContext(FormConfigContext);\n}\n\n/**\n * The Alert component the form chrome should render — the consumer's override\n * from `<FormProvider components={{ alert }}>` if present, else the library\n * default. Use this everywhere instead of importing `Alert` directly so notices\n * stay customizable.\n */\nexport function useFormAlert(): ComponentType<AlertProps> {\n return useFormConfig().components?.alert ?? Alert;\n}\n"],"mappings":";;;;AAUA,MAAa,oBAAoB,cAA0B,EAAE,CAAC;AAE9D,SAAgB,gBAA4B;AAC1C,QAAO,WAAW,kBAAkB;;;;;;;;AAStC,SAAgB,eAA0C;AACxD,QAAO,eAAe,CAAC,YAAY,SAAS"}