@pipe0/react 1.0.31 → 1.0.33

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 (89) hide show
  1. package/CHANGELOG.md +23 -0
  2. package/dist/components/defaults/adapters/context-select-input.mjs +1 -0
  3. package/dist/components/defaults/adapters/context-select-input.mjs.map +1 -1
  4. package/dist/components/defaults/adapters/loose-object-input.mjs +2 -2
  5. package/dist/components/defaults/adapters/loose-object-input.mjs.map +1 -1
  6. package/dist/components/defaults/catalog/card-derived.d.mts +1 -1
  7. package/dist/components/defaults/catalog/card-derived.mjs +0 -1
  8. package/dist/components/defaults/catalog/card-derived.mjs.map +1 -1
  9. package/dist/components/defaults/catalog/card-primitives.d.mts +2 -2
  10. package/dist/components/defaults/catalog/card-primitives.mjs +2 -2
  11. package/dist/components/defaults/catalog/card-primitives.mjs.map +1 -1
  12. package/dist/components/internal/LiquidEditor/ChipEditPopover.mjs +60 -14
  13. package/dist/components/internal/LiquidEditor/ChipEditPopover.mjs.map +1 -1
  14. package/dist/context/catalog-card-context.mjs +3 -7
  15. package/dist/context/catalog-card-context.mjs.map +1 -1
  16. package/dist/context/catalog-config-context.d.mts +1 -1
  17. package/dist/context/catalog-config-context.mjs +1 -1
  18. package/dist/context/catalog-config-context.mjs.map +1 -1
  19. package/dist/hooks/catalog-table.d.mts.map +1 -1
  20. package/dist/hooks/catalog-table.mjs +13 -2
  21. package/dist/hooks/catalog-table.mjs.map +1 -1
  22. package/dist/hooks/use-pipe-catalog-table.d.mts +8 -8
  23. package/dist/index.d.mts +2 -17
  24. package/dist/index.mjs +1 -16
  25. package/dist/styles/pipe0-form.css +1 -1
  26. package/dist/types/catalog-adapters.d.mts +2 -19
  27. package/dist/types/catalog-adapters.d.mts.map +1 -1
  28. package/package.json +2 -2
  29. package/dist/components/compound/searches-catalog/active-filters.d.mts +0 -23
  30. package/dist/components/compound/searches-catalog/active-filters.d.mts.map +0 -1
  31. package/dist/components/compound/searches-catalog/active-filters.mjs +0 -50
  32. package/dist/components/compound/searches-catalog/active-filters.mjs.map +0 -1
  33. package/dist/components/compound/searches-catalog/card.d.mts +0 -22
  34. package/dist/components/compound/searches-catalog/card.d.mts.map +0 -1
  35. package/dist/components/compound/searches-catalog/card.mjs +0 -82
  36. package/dist/components/compound/searches-catalog/card.mjs.map +0 -1
  37. package/dist/components/compound/searches-catalog/category-filter.d.mts +0 -27
  38. package/dist/components/compound/searches-catalog/category-filter.d.mts.map +0 -1
  39. package/dist/components/compound/searches-catalog/category-filter.mjs +0 -61
  40. package/dist/components/compound/searches-catalog/category-filter.mjs.map +0 -1
  41. package/dist/components/compound/searches-catalog/column-filter.d.mts +0 -29
  42. package/dist/components/compound/searches-catalog/column-filter.d.mts.map +0 -1
  43. package/dist/components/compound/searches-catalog/column-filter.mjs +0 -64
  44. package/dist/components/compound/searches-catalog/column-filter.mjs.map +0 -1
  45. package/dist/components/compound/searches-catalog/column-filters.d.mts +0 -15
  46. package/dist/components/compound/searches-catalog/column-filters.d.mts.map +0 -1
  47. package/dist/components/compound/searches-catalog/column-filters.mjs +0 -16
  48. package/dist/components/compound/searches-catalog/column-filters.mjs.map +0 -1
  49. package/dist/components/compound/searches-catalog/empty.d.mts +0 -17
  50. package/dist/components/compound/searches-catalog/empty.d.mts.map +0 -1
  51. package/dist/components/compound/searches-catalog/empty.mjs +0 -29
  52. package/dist/components/compound/searches-catalog/empty.mjs.map +0 -1
  53. package/dist/components/compound/searches-catalog/index.d.mts +0 -12
  54. package/dist/components/compound/searches-catalog/list.d.mts +0 -19
  55. package/dist/components/compound/searches-catalog/list.d.mts.map +0 -1
  56. package/dist/components/compound/searches-catalog/list.mjs +0 -33
  57. package/dist/components/compound/searches-catalog/list.mjs.map +0 -1
  58. package/dist/components/compound/searches-catalog/output-field-filter.d.mts +0 -22
  59. package/dist/components/compound/searches-catalog/output-field-filter.d.mts.map +0 -1
  60. package/dist/components/compound/searches-catalog/output-field-filter.mjs +0 -22
  61. package/dist/components/compound/searches-catalog/output-field-filter.mjs.map +0 -1
  62. package/dist/components/compound/searches-catalog/provider-filter.d.mts +0 -22
  63. package/dist/components/compound/searches-catalog/provider-filter.d.mts.map +0 -1
  64. package/dist/components/compound/searches-catalog/provider-filter.mjs +0 -29
  65. package/dist/components/compound/searches-catalog/provider-filter.mjs.map +0 -1
  66. package/dist/components/compound/searches-catalog/root.d.mts +0 -33
  67. package/dist/components/compound/searches-catalog/root.d.mts.map +0 -1
  68. package/dist/components/compound/searches-catalog/root.mjs +0 -74
  69. package/dist/components/compound/searches-catalog/root.mjs.map +0 -1
  70. package/dist/components/compound/searches-catalog/search-filter.d.mts +0 -21
  71. package/dist/components/compound/searches-catalog/search-filter.d.mts.map +0 -1
  72. package/dist/components/compound/searches-catalog/search-filter.mjs +0 -47
  73. package/dist/components/compound/searches-catalog/search-filter.mjs.map +0 -1
  74. package/dist/components/compound/searches-catalog/tag-filter.d.mts +0 -22
  75. package/dist/components/compound/searches-catalog/tag-filter.d.mts.map +0 -1
  76. package/dist/components/compound/searches-catalog/tag-filter.mjs +0 -22
  77. package/dist/components/compound/searches-catalog/tag-filter.mjs.map +0 -1
  78. package/dist/context/searches-catalog-card-context.d.mts +0 -24
  79. package/dist/context/searches-catalog-card-context.d.mts.map +0 -1
  80. package/dist/context/searches-catalog-card-context.mjs +0 -13
  81. package/dist/context/searches-catalog-card-context.mjs.map +0 -1
  82. package/dist/context/searches-catalog-context.d.mts +0 -20
  83. package/dist/context/searches-catalog-context.d.mts.map +0 -1
  84. package/dist/context/searches-catalog-context.mjs +0 -13
  85. package/dist/context/searches-catalog-context.mjs.map +0 -1
  86. package/dist/hooks/use-searches-catalog-table.d.mts +0 -56
  87. package/dist/hooks/use-searches-catalog-table.d.mts.map +0 -1
  88. package/dist/hooks/use-searches-catalog-table.mjs +0 -159
  89. package/dist/hooks/use-searches-catalog-table.mjs.map +0 -1
package/CHANGELOG.md CHANGED
@@ -1,5 +1,28 @@
1
1
  # @pipe0/elements-react
2
2
 
3
+ ## 1.0.33
4
+
5
+ ### Patch Changes
6
+
7
+ - e50e746: feat: fix update row
8
+ - e50e746: Remove /run and /searches
9
+ - Updated dependencies [e50e746]
10
+ - Updated dependencies [e50e746]
11
+ - @pipe0/base@1.0.33
12
+
13
+ ## 1.0.32
14
+
15
+ ### Patch Changes
16
+
17
+ - 425275c: Add nooks
18
+ - 36ad813: Add instantly
19
+
20
+ lead:enroll:lemlist@1 now matches the Amplemarket and Instantly enroll pipes: input fields are only email and profile_url, and every sequence variable (lemlist's own firstName/companyName included) is set via custom_variables. Fields referenced by custom variables are required inputs for all three enroll pipes.
21
+
22
+ - Updated dependencies [425275c]
23
+ - Updated dependencies [36ad813]
24
+ - @pipe0/base@1.0.32
25
+
3
26
  ## 1.0.31
4
27
 
5
28
  ### Patch Changes
@@ -200,6 +200,7 @@ function ContextSelectInputAdapter(field) {
200
200
  single: true,
201
201
  value: field.selectedValue ? [field.selectedValue] : [],
202
202
  onChange: (next) => field.onSelect(next.at(-1) ?? ""),
203
+ options: field.options,
203
204
  loadOptions: field.loadOptions,
204
205
  labelFor,
205
206
  disabled: field.pending,
@@ -1 +1 @@
1
- {"version":3,"file":"context-select-input.mjs","names":[],"sources":["../../../../src/components/defaults/adapters/context-select-input.tsx"],"sourcesContent":["import { type StoreOption, tryDecodeBucketContract } from \"@pipe0/base\";\nimport { useMemo, useState } from \"react\";\nimport { cn } from \"../../../lib/utils.js\";\nimport type { FieldHandle } from \"../../../types/field-handle.js\";\nimport { WidgetStrip } from \"../../../widgets/widget-strip.js\";\nimport { SuggestCombobox } from \"../../internal/combobox/suggest-combobox.js\";\nimport { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from \"../../ui/select.js\";\n\ntype MappingEntry = { field_name: string; entry_field?: string };\n\n/**\n * Compound variant (`meta.mappingPath` set — the bucket input): one component\n * owning the slug select/create AND the entry-field mapping + contract at\n * sibling paths. Two modes, decided by the contract:\n *\n * - EXISTING bucket (selected option carries `data.contract`): the bucket's\n * schema fields are listed, each mapped to a row column (same-named columns\n * prefill).\n * - NEW slug (created via `Add \"<name>\"`): a plain fields picker — the picked\n * column names become the new bucket's schema on first write.\n *\n * The sibling paths are unregistered in the payload schema (they render no\n * input of their own), so this adapter is their only writer — local state\n * mirrors them and `form.setValue` keeps the payload in sync.\n */\nfunction MappedContextSelect(field: FieldHandle<\"context_select_input\">) {\n const meta = field.meta;\n const mappingPath = meta.mappingPath as string;\n const contractPath = meta.contractPath as string;\n const fieldOptions = meta.fieldOptions ?? [];\n const keyLabel = meta.keyLabel ?? \"Field\";\n\n const [mapping, setMappingState] = useState<MappingEntry[]>(\n () => (field.form.getValues(mappingPath) as MappingEntry[]) ?? [],\n );\n const [contract, setContractState] = useState<string>(\n () => (field.form.getValues(contractPath) as string) ?? \"\",\n );\n const writeMapping = (next: MappingEntry[]) => {\n setMappingState(next);\n field.form.setValue(mappingPath, next, { shouldDirty: true, shouldTouch: true });\n };\n const writeContract = (next: string) => {\n setContractState(next);\n field.form.setValue(contractPath, next, { shouldDirty: true, shouldTouch: true });\n };\n\n const schema = useMemo(() => tryDecodeBucketContract(contract), [contract]);\n\n const onPick = (value: string) => {\n field.onSelect(value);\n if (!value) {\n writeContract(\"\");\n writeMapping([]);\n return;\n }\n const option = field.options.find((o) => o.value === value);\n const optionContract = option?.data?.contract ?? \"\";\n writeContract(optionContract);\n const optionSchema = tryDecodeBucketContract(optionContract);\n if (optionSchema) {\n // Existing bucket: one mapping row per schema field, prefilled with the\n // same-named row column when it exists.\n writeMapping(\n Object.keys(optionSchema.input_fields).map((bucketField) => ({\n field_name: fieldOptions.some((o) => o.value === bucketField) ? bucketField : \"\",\n entry_field: bucketField,\n })),\n );\n } else {\n // Freshly created slug: start with an empty picker.\n writeMapping([]);\n }\n };\n\n return (\n <div\n data-p0=\"input\"\n className={cn(\"pz:flex pz:flex-col pz:gap-2\", field.pending && \"pz:opacity-60\")}\n >\n <SuggestCombobox\n value={field.selectedValue ? [field.selectedValue] : []}\n onChange={(next) => onPick(next.at(-1) ?? \"\")}\n options={field.options}\n allowCreate\n disabled={field.pending}\n ariaInvalid={!!field.error}\n placeholder={field.pending ? \"Loading…\" : (field.meta.placeholder ?? \"\")}\n emptyLabel=\"Type a name to create one\"\n />\n {field.suggestionsDisabled && (\n <div className=\"pz:text-xs pz:text-muted-foreground pz:italic\">\n {field.suggestionsDisabledReason ?? \"Suggestions unavailable\"}\n </div>\n )}\n\n {field.selectedValue && schema && (\n <div className=\"pz:flex pz:flex-col pz:gap-1\">\n <p className=\"pz:text-xs pz:text-muted-foreground\">\n A bucket entry is identified by the field\n {Object.keys(schema.input_fields).length > 1 ? \"s\" : \"\"} below. Pick the row column that\n supplies each one.\n </p>\n {mapping.map((entry, idx) => (\n <div\n key={entry.entry_field ?? entry.field_name}\n className=\"pz:flex pz:items-center pz:gap-2\"\n >\n <span\n className=\"pz:basis-1/3 pz:truncate pz:text-xs pz:text-muted-foreground\"\n title={entry.entry_field}\n >\n {entry.entry_field} ←\n </span>\n <div className=\"pz:flex-1\">\n <SuggestCombobox\n value={entry.field_name ? [entry.field_name] : []}\n onChange={(next) =>\n writeMapping(\n mapping.map((m, j) =>\n j === idx ? { ...m, field_name: next.at(-1) ?? \"\" } : m,\n ),\n )\n }\n options={fieldOptions}\n ariaInvalid={!entry.field_name}\n placeholder={`Column for ${keyLabel.toLowerCase()} \"${entry.entry_field}\"…`}\n emptyLabel=\"No columns available\"\n />\n </div>\n </div>\n ))}\n </div>\n )}\n\n {field.selectedValue && !schema && (\n <div className=\"pz:flex pz:flex-col pz:gap-1\">\n <p className=\"pz:text-xs pz:text-muted-foreground\">\n New bucket: pick the column(s) that identify an entry. Their names become the bucket's\n schema when it is created on first write.\n </p>\n <SuggestCombobox\n value={mapping.map((m) => m.field_name)}\n onChange={(next) => writeMapping(next.map((field_name) => ({ field_name })))}\n options={fieldOptions}\n ariaInvalid={mapping.length === 0}\n placeholder=\"Select identifying columns…\"\n emptyLabel=\"No columns available\"\n reorderable\n />\n </div>\n )}\n </div>\n );\n}\n\n/**\n * `meta.multiple` variant: a token multiselect writing `string[]` (the value\n * schema is `string | string[]`). The FieldHandle's `selectedValue`/`onSelect`\n * are single-string, so — like the compound variant — this writes through\n * `field.form.setValue` directly.\n */\nfunction MultipleContextSelect(field: FieldHandle<\"context_select_input\">) {\n const [selected, setSelected] = useState<string[]>(() => {\n const raw = field.form.getValues(field.path) as string | string[] | undefined;\n return Array.isArray(raw) ? raw : raw ? [raw] : [];\n });\n const write = (next: string[]) => {\n setSelected(next);\n field.form.setValue(field.path, next, {\n shouldDirty: true,\n shouldTouch: true,\n shouldValidate: true,\n });\n };\n const labelFor = (value: string) => field.options.find((o) => o.value === value)?.label ?? value;\n\n return (\n <div\n data-p0=\"input\"\n className={cn(\"pz:flex pz:flex-col pz:gap-1\", field.pending && \"pz:opacity-60\")}\n >\n <SuggestCombobox\n value={selected}\n onChange={write}\n options={field.loadOptions ? undefined : field.options}\n loadOptions={field.loadOptions}\n labelFor={labelFor}\n disabled={field.pending}\n ariaInvalid={!!field.error}\n placeholder={field.pending ? \"Loading…\" : (field.meta.placeholder ?? \"\")}\n emptyLabel=\"No matches\"\n />\n {field.suggestionsDisabled && (\n <div className=\"pz:text-xs pz:gap-y-1 pz:text-muted-foreground pz:italic\">\n {field.suggestionsDisabledReason ?? \"Suggestions unavailable\"}{\" \"}\n </div>\n )}\n </div>\n );\n}\n\nexport function ContextSelectInputAdapter(field: FieldHandle<\"context_select_input\">) {\n const hasOptions = field.options.length > 0;\n const selectedOption = field.options.find((o) => o.value === field.selectedValue);\n\n // Compound variant: slug + dependent entry-field mapping (see MappedContextSelect).\n if (field.meta.mappingPath) {\n return <MappedContextSelect {...field} />;\n }\n\n // Token-multiselect variant (`meta.multiple`): value is `string[]`.\n if (field.meta.multiple) {\n return <MultipleContextSelect {...field} />;\n }\n\n // Label lookup for the selected chip: prefer the store-fetched option's\n // label; async search results aren't retained, so fall back to the value.\n const labelFor = (value: string) => field.options.find((o) => o.value === value)?.label ?? value;\n\n // Creatable variant: a single-select combobox where typing an unknown value\n // offers an inline `Add \"<name>\"` row. Selection REPLACES (no maxItems gate —\n // that would require removing the chip before picking another option).\n if (field.meta.allowCreate) {\n return (\n <div\n data-p0=\"input\"\n className={cn(\"pz:flex pz:flex-col pz:gap-1\", field.pending && \"pz:opacity-60\")}\n >\n <SuggestCombobox\n single\n value={field.selectedValue ? [field.selectedValue] : []}\n onChange={(next) => field.onSelect(next.at(-1) ?? \"\")}\n // Server-side search when the host wires getFieldContext; the\n // fetched set is only the first page, so local filtering is a\n // fallback, not the primary path.\n options={field.loadOptions ? undefined : field.options}\n loadOptions={field.loadOptions}\n labelFor={labelFor}\n allowCreate\n disabled={field.pending}\n ariaInvalid={!!field.error}\n placeholder={field.pending ? \"Loading…\" : (field.meta.placeholder ?? \"\")}\n emptyLabel=\"Type a name to create one\"\n />\n {field.suggestionsDisabled && (\n <div className=\"pz:text-xs pz:gap-y-1 pz:text-muted-foreground pz:italic\">\n {field.suggestionsDisabledReason ?? \"Suggestions unavailable\"}{\" \"}\n </div>\n )}\n </div>\n );\n }\n\n // Searchable variant: with a field-context searcher wired, a plain list\n // can't surface more than the first fetched page — render a single-select\n // combobox whose options come from the server per keystroke (debounced,\n // SWR-cached).\n if (field.loadOptions && !field.suggestionsDisabled) {\n return (\n <div\n data-p0=\"input\"\n className={cn(\"pz:flex pz:flex-col pz:gap-1\", field.pending && \"pz:opacity-60\")}\n >\n <SuggestCombobox\n single\n value={field.selectedValue ? [field.selectedValue] : []}\n onChange={(next) => field.onSelect(next.at(-1) ?? \"\")}\n loadOptions={field.loadOptions}\n labelFor={labelFor}\n disabled={field.pending}\n ariaInvalid={!!field.error}\n placeholder={field.pending ? \"Loading…\" : (field.meta.placeholder ?? \"Search…\")}\n emptyLabel=\"No matches\"\n />\n </div>\n );\n }\n\n // ONE always-controlled Select across every state (loading / gated / ready).\n // Rendering a separate <Select> tree per state — or using\n // `value={... || undefined}` — flips Base UI between uncontrolled and\n // controlled, which warns and now actually fires on the loading→ready\n // transition (the field finally re-renders through it). `null` is Base UI's\n // controlled \"no selection\" sentinel (cf. connector-input + the `v === null`\n // guard below), so the value is never `undefined` and the control stays\n // controlled for its whole lifetime. State differences are expressed only via\n // `disabled` / `placeholder` / the helper line below — not via remounting.\n const placeholder = field.pending ? \"Loading…\" : (field.meta.placeholder ?? \"\");\n\n return (\n <div\n data-p0=\"input\"\n className={cn(\"pz:flex pz:flex-col pz:gap-1\", field.pending && \"pz:opacity-60\")}\n >\n <Select\n value={field.selectedValue || null}\n onValueChange={(v) => {\n if (v === null) return;\n field.onSelect(v);\n }}\n name={field.path}\n disabled={field.pending || field.suggestionsDisabled || !hasOptions}\n >\n <SelectTrigger id={field.id} aria-invalid={!!field.error} className=\"pz:w-full\">\n <SelectValue placeholder={placeholder}>\n {selectedOption ? (\n <span className=\"pz:flex pz:items-center pz:gap-2\">\n <WidgetStrip widgets={selectedOption.widgets} />\n <span>{selectedOption.label}</span>\n </span>\n ) : undefined}\n </SelectValue>\n </SelectTrigger>\n <SelectContent>\n {field.options.map((opt: StoreOption) => (\n <SelectItem key={opt.value} value={opt.value} label={opt.label}>\n <span className=\"pz:flex pz:items-center pz:gap-2\">\n <WidgetStrip widgets={opt.widgets} />\n <span>{opt.label}</span>\n </span>\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n {field.suggestionsDisabled ? (\n <div className=\"pz:text-xs pz:gap-y-1 pz:text-muted-foreground pz:italic\">\n {field.suggestionsDisabledReason ?? \"Suggestions unavailable\"}{\" \"}\n </div>\n ) : !field.pending && !hasOptions ? (\n <span className=\"pz:text-xs pz:text-muted-foreground\">No fields available</span>\n ) : null}\n </div>\n );\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"context-select-input.mjs","names":[],"sources":["../../../../src/components/defaults/adapters/context-select-input.tsx"],"sourcesContent":["import { type StoreOption, tryDecodeBucketContract } from \"@pipe0/base\";\nimport { useMemo, useState } from \"react\";\nimport { cn } from \"../../../lib/utils.js\";\nimport type { FieldHandle } from \"../../../types/field-handle.js\";\nimport { WidgetStrip } from \"../../../widgets/widget-strip.js\";\nimport { SuggestCombobox } from \"../../internal/combobox/suggest-combobox.js\";\nimport { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from \"../../ui/select.js\";\n\ntype MappingEntry = { field_name: string; entry_field?: string };\n\n/**\n * Compound variant (`meta.mappingPath` set — the bucket input): one component\n * owning the slug select/create AND the entry-field mapping + contract at\n * sibling paths. Two modes, decided by the contract:\n *\n * - EXISTING bucket (selected option carries `data.contract`): the bucket's\n * schema fields are listed, each mapped to a row column (same-named columns\n * prefill).\n * - NEW slug (created via `Add \"<name>\"`): a plain fields picker — the picked\n * column names become the new bucket's schema on first write.\n *\n * The sibling paths are unregistered in the payload schema (they render no\n * input of their own), so this adapter is their only writer — local state\n * mirrors them and `form.setValue` keeps the payload in sync.\n */\nfunction MappedContextSelect(field: FieldHandle<\"context_select_input\">) {\n const meta = field.meta;\n const mappingPath = meta.mappingPath as string;\n const contractPath = meta.contractPath as string;\n const fieldOptions = meta.fieldOptions ?? [];\n const keyLabel = meta.keyLabel ?? \"Field\";\n\n const [mapping, setMappingState] = useState<MappingEntry[]>(\n () => (field.form.getValues(mappingPath) as MappingEntry[]) ?? [],\n );\n const [contract, setContractState] = useState<string>(\n () => (field.form.getValues(contractPath) as string) ?? \"\",\n );\n const writeMapping = (next: MappingEntry[]) => {\n setMappingState(next);\n field.form.setValue(mappingPath, next, { shouldDirty: true, shouldTouch: true });\n };\n const writeContract = (next: string) => {\n setContractState(next);\n field.form.setValue(contractPath, next, { shouldDirty: true, shouldTouch: true });\n };\n\n const schema = useMemo(() => tryDecodeBucketContract(contract), [contract]);\n\n const onPick = (value: string) => {\n field.onSelect(value);\n if (!value) {\n writeContract(\"\");\n writeMapping([]);\n return;\n }\n const option = field.options.find((o) => o.value === value);\n const optionContract = option?.data?.contract ?? \"\";\n writeContract(optionContract);\n const optionSchema = tryDecodeBucketContract(optionContract);\n if (optionSchema) {\n // Existing bucket: one mapping row per schema field, prefilled with the\n // same-named row column when it exists.\n writeMapping(\n Object.keys(optionSchema.input_fields).map((bucketField) => ({\n field_name: fieldOptions.some((o) => o.value === bucketField) ? bucketField : \"\",\n entry_field: bucketField,\n })),\n );\n } else {\n // Freshly created slug: start with an empty picker.\n writeMapping([]);\n }\n };\n\n return (\n <div\n data-p0=\"input\"\n className={cn(\"pz:flex pz:flex-col pz:gap-2\", field.pending && \"pz:opacity-60\")}\n >\n <SuggestCombobox\n value={field.selectedValue ? [field.selectedValue] : []}\n onChange={(next) => onPick(next.at(-1) ?? \"\")}\n options={field.options}\n allowCreate\n disabled={field.pending}\n ariaInvalid={!!field.error}\n placeholder={field.pending ? \"Loading…\" : (field.meta.placeholder ?? \"\")}\n emptyLabel=\"Type a name to create one\"\n />\n {field.suggestionsDisabled && (\n <div className=\"pz:text-xs pz:text-muted-foreground pz:italic\">\n {field.suggestionsDisabledReason ?? \"Suggestions unavailable\"}\n </div>\n )}\n\n {field.selectedValue && schema && (\n <div className=\"pz:flex pz:flex-col pz:gap-1\">\n <p className=\"pz:text-xs pz:text-muted-foreground\">\n A bucket entry is identified by the field\n {Object.keys(schema.input_fields).length > 1 ? \"s\" : \"\"} below. Pick the row column that\n supplies each one.\n </p>\n {mapping.map((entry, idx) => (\n <div\n key={entry.entry_field ?? entry.field_name}\n className=\"pz:flex pz:items-center pz:gap-2\"\n >\n <span\n className=\"pz:basis-1/3 pz:truncate pz:text-xs pz:text-muted-foreground\"\n title={entry.entry_field}\n >\n {entry.entry_field} ←\n </span>\n <div className=\"pz:flex-1\">\n <SuggestCombobox\n value={entry.field_name ? [entry.field_name] : []}\n onChange={(next) =>\n writeMapping(\n mapping.map((m, j) =>\n j === idx ? { ...m, field_name: next.at(-1) ?? \"\" } : m,\n ),\n )\n }\n options={fieldOptions}\n ariaInvalid={!entry.field_name}\n placeholder={`Column for ${keyLabel.toLowerCase()} \"${entry.entry_field}\"…`}\n emptyLabel=\"No columns available\"\n />\n </div>\n </div>\n ))}\n </div>\n )}\n\n {field.selectedValue && !schema && (\n <div className=\"pz:flex pz:flex-col pz:gap-1\">\n <p className=\"pz:text-xs pz:text-muted-foreground\">\n New bucket: pick the column(s) that identify an entry. Their names become the bucket's\n schema when it is created on first write.\n </p>\n <SuggestCombobox\n value={mapping.map((m) => m.field_name)}\n onChange={(next) => writeMapping(next.map((field_name) => ({ field_name })))}\n options={fieldOptions}\n ariaInvalid={mapping.length === 0}\n placeholder=\"Select identifying columns…\"\n emptyLabel=\"No columns available\"\n reorderable\n />\n </div>\n )}\n </div>\n );\n}\n\n/**\n * `meta.multiple` variant: a token multiselect writing `string[]` (the value\n * schema is `string | string[]`). The FieldHandle's `selectedValue`/`onSelect`\n * are single-string, so — like the compound variant — this writes through\n * `field.form.setValue` directly.\n */\nfunction MultipleContextSelect(field: FieldHandle<\"context_select_input\">) {\n const [selected, setSelected] = useState<string[]>(() => {\n const raw = field.form.getValues(field.path) as string | string[] | undefined;\n return Array.isArray(raw) ? raw : raw ? [raw] : [];\n });\n const write = (next: string[]) => {\n setSelected(next);\n field.form.setValue(field.path, next, {\n shouldDirty: true,\n shouldTouch: true,\n shouldValidate: true,\n });\n };\n const labelFor = (value: string) => field.options.find((o) => o.value === value)?.label ?? value;\n\n return (\n <div\n data-p0=\"input\"\n className={cn(\"pz:flex pz:flex-col pz:gap-1\", field.pending && \"pz:opacity-60\")}\n >\n <SuggestCombobox\n value={selected}\n onChange={write}\n options={field.loadOptions ? undefined : field.options}\n loadOptions={field.loadOptions}\n labelFor={labelFor}\n disabled={field.pending}\n ariaInvalid={!!field.error}\n placeholder={field.pending ? \"Loading…\" : (field.meta.placeholder ?? \"\")}\n emptyLabel=\"No matches\"\n />\n {field.suggestionsDisabled && (\n <div className=\"pz:text-xs pz:gap-y-1 pz:text-muted-foreground pz:italic\">\n {field.suggestionsDisabledReason ?? \"Suggestions unavailable\"}{\" \"}\n </div>\n )}\n </div>\n );\n}\n\nexport function ContextSelectInputAdapter(field: FieldHandle<\"context_select_input\">) {\n const hasOptions = field.options.length > 0;\n const selectedOption = field.options.find((o) => o.value === field.selectedValue);\n\n // Compound variant: slug + dependent entry-field mapping (see MappedContextSelect).\n if (field.meta.mappingPath) {\n return <MappedContextSelect {...field} />;\n }\n\n // Token-multiselect variant (`meta.multiple`): value is `string[]`.\n if (field.meta.multiple) {\n return <MultipleContextSelect {...field} />;\n }\n\n // Label lookup for the selected chip: prefer the store-fetched option's\n // label; async search results aren't retained, so fall back to the value.\n const labelFor = (value: string) => field.options.find((o) => o.value === value)?.label ?? value;\n\n // Creatable variant: a single-select combobox where typing an unknown value\n // offers an inline `Add \"<name>\"` row. Selection REPLACES (no maxItems gate —\n // that would require removing the chip before picking another option).\n if (field.meta.allowCreate) {\n return (\n <div\n data-p0=\"input\"\n className={cn(\"pz:flex pz:flex-col pz:gap-1\", field.pending && \"pz:opacity-60\")}\n >\n <SuggestCombobox\n single\n value={field.selectedValue ? [field.selectedValue] : []}\n onChange={(next) => field.onSelect(next.at(-1) ?? \"\")}\n // Server-side search when the host wires getFieldContext; the\n // fetched set is only the first page, so local filtering is a\n // fallback, not the primary path.\n options={field.loadOptions ? undefined : field.options}\n loadOptions={field.loadOptions}\n labelFor={labelFor}\n allowCreate\n disabled={field.pending}\n ariaInvalid={!!field.error}\n placeholder={field.pending ? \"Loading…\" : (field.meta.placeholder ?? \"\")}\n emptyLabel=\"Type a name to create one\"\n />\n {field.suggestionsDisabled && (\n <div className=\"pz:text-xs pz:gap-y-1 pz:text-muted-foreground pz:italic\">\n {field.suggestionsDisabledReason ?? \"Suggestions unavailable\"}{\" \"}\n </div>\n )}\n </div>\n );\n }\n\n // Searchable variant: with a field-context searcher wired, a plain list\n // can't surface more than the first fetched page — render a single-select\n // combobox whose options come from the server per keystroke (debounced,\n // SWR-cached).\n if (field.loadOptions && !field.suggestionsDisabled) {\n return (\n <div\n data-p0=\"input\"\n className={cn(\"pz:flex pz:flex-col pz:gap-1\", field.pending && \"pz:opacity-60\")}\n >\n <SuggestCombobox\n single\n value={field.selectedValue ? [field.selectedValue] : []}\n onChange={(next) => field.onSelect(next.at(-1) ?? \"\")}\n // Suggestions still come from `loadOptions`; the store-fetched\n // options resolve the selected value's label AND widgets (logo).\n options={field.options}\n loadOptions={field.loadOptions}\n labelFor={labelFor}\n disabled={field.pending}\n ariaInvalid={!!field.error}\n placeholder={field.pending ? \"Loading…\" : (field.meta.placeholder ?? \"Search…\")}\n emptyLabel=\"No matches\"\n />\n </div>\n );\n }\n\n // ONE always-controlled Select across every state (loading / gated / ready).\n // Rendering a separate <Select> tree per state — or using\n // `value={... || undefined}` — flips Base UI between uncontrolled and\n // controlled, which warns and now actually fires on the loading→ready\n // transition (the field finally re-renders through it). `null` is Base UI's\n // controlled \"no selection\" sentinel (cf. connector-input + the `v === null`\n // guard below), so the value is never `undefined` and the control stays\n // controlled for its whole lifetime. State differences are expressed only via\n // `disabled` / `placeholder` / the helper line below — not via remounting.\n const placeholder = field.pending ? \"Loading…\" : (field.meta.placeholder ?? \"\");\n\n return (\n <div\n data-p0=\"input\"\n className={cn(\"pz:flex pz:flex-col pz:gap-1\", field.pending && \"pz:opacity-60\")}\n >\n <Select\n value={field.selectedValue || null}\n onValueChange={(v) => {\n if (v === null) return;\n field.onSelect(v);\n }}\n name={field.path}\n disabled={field.pending || field.suggestionsDisabled || !hasOptions}\n >\n <SelectTrigger id={field.id} aria-invalid={!!field.error} className=\"pz:w-full\">\n <SelectValue placeholder={placeholder}>\n {selectedOption ? (\n <span className=\"pz:flex pz:items-center pz:gap-2\">\n <WidgetStrip widgets={selectedOption.widgets} />\n <span>{selectedOption.label}</span>\n </span>\n ) : undefined}\n </SelectValue>\n </SelectTrigger>\n <SelectContent>\n {field.options.map((opt: StoreOption) => (\n <SelectItem key={opt.value} value={opt.value} label={opt.label}>\n <span className=\"pz:flex pz:items-center pz:gap-2\">\n <WidgetStrip widgets={opt.widgets} />\n <span>{opt.label}</span>\n </span>\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n {field.suggestionsDisabled ? (\n <div className=\"pz:text-xs pz:gap-y-1 pz:text-muted-foreground pz:italic\">\n {field.suggestionsDisabledReason ?? \"Suggestions unavailable\"}{\" \"}\n </div>\n ) : !field.pending && !hasOptions ? (\n <span className=\"pz:text-xs pz:text-muted-foreground\">No fields available</span>\n ) : null}\n </div>\n );\n}\n"],"mappings":"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"}
@@ -57,7 +57,7 @@ function LooseObjectInputAdapter(field) {
57
57
  className: "pz:flex pz:items-start pz:gap-2",
58
58
  children: [
59
59
  /* @__PURE__ */ jsx("div", {
60
- className: "pz:basis-1/3",
60
+ className: "pz:basis-1/3 pz:shrink-0",
61
61
  children: /* @__PURE__ */ jsx(Input, {
62
62
  defaultValue: key,
63
63
  onBlur: (e) => renameKey(key, e.target.value),
@@ -65,7 +65,7 @@ function LooseObjectInputAdapter(field) {
65
65
  })
66
66
  }),
67
67
  /* @__PURE__ */ jsx("div", {
68
- className: "pz:flex-1 pz:rounded-md pz:border pz:border-input pz:bg-transparent",
68
+ className: "pz:min-w-0 pz:flex-1 pz:wrap-anywhere pz:rounded-md pz:border pz:border-input pz:bg-transparent",
69
69
  children: /* @__PURE__ */ jsx(LiquidEditor, {
70
70
  value: val,
71
71
  onChange: (v) => setEntryValue(key, v),
@@ -1 +1 @@
1
- {"version":3,"file":"loose-object-input.mjs","names":[],"sources":["../../../../src/components/defaults/adapters/loose-object-input.tsx"],"sourcesContent":["import { Plus, X } from \"lucide-react\";\nimport type { FieldHandle } from \"../../../types/field-handle.js\";\nimport { FieldLegend } from \"../../internal/field-legend.js\";\nimport { LiquidEditor } from \"../../internal/LiquidEditor/LiquidEditor.js\";\nimport { Button } from \"../../ui/button.js\";\nimport { Input } from \"../../ui/input.js\";\n\n/**\n * Adapter for `pipesLooseObjectInput`. The form value is a plain\n * `Record<string, string>`; each entry renders as a row. The key is the\n * object key, so it's a literal text input (committed on blur, which is when\n * the row's React key — the object key — changes). The value cell uses\n * `LiquidEditor` so it supports `/` references (input fields + secrets +\n * constants). Empty and duplicate keys aren't meaningful for an object and\n * aren't supported; `maxKeys` bounds the number of entries.\n *\n * The per-cell legend would otherwise render once per value cell — too noisy.\n * The value editors run with `hideLegend`; a single legend renders below the\n * list.\n */\nexport function LooseObjectInputAdapter(field: FieldHandle<\"loose_object_input\">) {\n const { value, setObject, searchSecrets, searchConstants, meta } = field;\n const entries = Object.entries(value);\n const maxKeys = meta.maxKeys ?? 50;\n const canAdd = entries.length < maxKeys;\n\n // Rebuild the object, renaming `oldKey`→`newKey` in place (order preserved).\n const renameKey = (oldKey: string, newKey: string) => {\n if (newKey === oldKey) return;\n const next: Record<string, string> = {};\n for (const [k, v] of Object.entries(value)) next[k === oldKey ? newKey : k] = v;\n setObject(next);\n };\n const setEntryValue = (key: string, v: string) => setObject({ ...value, [key]: v });\n const removeKey = (key: string) => {\n const { [key]: _removed, ...rest } = value;\n setObject(rest);\n };\n // One blank slot at a time — fill its key before adding another.\n const addEntry = () => {\n if (Object.hasOwn(value, \"\")) return;\n setObject({ ...value, \"\": \"\" });\n };\n\n return (\n <div data-p0=\"input\" className=\"pz:flex pz:flex-col pz:gap-2\">\n {entries.length === 0 && (\n <p className=\"pz:text-xs pz:text-muted-foreground\">\n {meta.keyLabel ? `No ${meta.keyLabel.toLowerCase()}s yet.` : \"No entries yet.\"}\n </p>\n )}\n {entries.map(([key, val]) => (\n <div key={key} className=\"pz:flex pz:items-start pz:gap-2\">\n <div className=\"pz:basis-1/3\">\n <Input\n defaultValue={key}\n onBlur={(e) => renameKey(key, e.target.value)}\n placeholder={meta.keyPlaceholder ?? meta.keyLabel ?? \"Key\"}\n />\n </div>\n <div className=\"pz:flex-1 pz:rounded-md pz:border pz:border-input pz:bg-transparent\">\n <LiquidEditor\n value={val}\n onChange={(v) => setEntryValue(key, v)}\n inputFields={meta.inputFields ?? []}\n searchSecrets={searchSecrets}\n searchConstants={searchConstants}\n placeholder={meta.valuePlaceholder ?? meta.valueLabel ?? \"Value\"}\n hideLegend\n />\n </div>\n <Button\n type=\"button\"\n variant=\"ghost\"\n size=\"icon\"\n aria-label=\"Remove row\"\n onClick={() => removeKey(key)}\n >\n <X className=\"pz:size-4\" />\n </Button>\n </div>\n ))}\n {entries.length > 0 && (\n <FieldLegend entries={[{ key: \"/\", label: \"to insert a reference\" }]} />\n )}\n <div>\n <Button type=\"button\" variant=\"outline\" size=\"sm\" onClick={addEntry} disabled={!canAdd}>\n <Plus className=\"pz:size-4 pz:mr-1\" />\n Add {meta.keyLabel ?? \"row\"}\n </Button>\n </div>\n </div>\n );\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;AAoBA,SAAgB,wBAAwB,OAA0C;CAChF,MAAM,EAAE,OAAO,WAAW,eAAe,iBAAiB,SAAS;CACnE,MAAM,UAAU,OAAO,QAAQ,MAAM;CACrC,MAAM,UAAU,KAAK,WAAW;CAChC,MAAM,SAAS,QAAQ,SAAS;CAGhC,MAAM,aAAa,QAAgB,WAAmB;AACpD,MAAI,WAAW,OAAQ;EACvB,MAAM,OAA+B,EAAE;AACvC,OAAK,MAAM,CAAC,GAAG,MAAM,OAAO,QAAQ,MAAM,CAAE,MAAK,MAAM,SAAS,SAAS,KAAK;AAC9E,YAAU,KAAK;;CAEjB,MAAM,iBAAiB,KAAa,MAAc,UAAU;EAAE,GAAG;GAAQ,MAAM;EAAG,CAAC;CACnF,MAAM,aAAa,QAAgB;EACjC,MAAM,GAAG,MAAM,UAAU,GAAG,SAAS;AACrC,YAAU,KAAK;;CAGjB,MAAM,iBAAiB;AACrB,MAAI,OAAO,OAAO,OAAO,GAAG,CAAE;AAC9B,YAAU;GAAE,GAAG;GAAO,IAAI;GAAI,CAAC;;AAGjC,QACE,qBAAC,OAAD;EAAK,WAAQ;EAAQ,WAAU;YAA/B;GACG,QAAQ,WAAW,KAClB,oBAAC,KAAD;IAAG,WAAU;cACV,KAAK,WAAW,MAAM,KAAK,SAAS,aAAa,CAAC,UAAU;IAC3D;GAEL,QAAQ,KAAK,CAAC,KAAK,SAClB,qBAAC,OAAD;IAAe,WAAU;cAAzB;KACE,oBAAC,OAAD;MAAK,WAAU;gBACb,oBAAC,OAAD;OACE,cAAc;OACd,SAAS,MAAM,UAAU,KAAK,EAAE,OAAO,MAAM;OAC7C,aAAa,KAAK,kBAAkB,KAAK,YAAY;OACrD;MACE;KACN,oBAAC,OAAD;MAAK,WAAU;gBACb,oBAAC,cAAD;OACE,OAAO;OACP,WAAW,MAAM,cAAc,KAAK,EAAE;OACtC,aAAa,KAAK,eAAe,EAAE;OACpB;OACE;OACjB,aAAa,KAAK,oBAAoB,KAAK,cAAc;OACzD;OACA;MACE;KACN,oBAAC,QAAD;MACE,MAAK;MACL,SAAQ;MACR,MAAK;MACL,cAAW;MACX,eAAe,UAAU,IAAI;gBAE7B,oBAAC,GAAD,EAAG,WAAU,aAAc;MACpB;KACL;MA5BI,IA4BJ,CACN;GACD,QAAQ,SAAS,KAChB,oBAAC,aAAD,EAAa,SAAS,CAAC;IAAE,KAAK;IAAK,OAAO;IAAyB,CAAC,EAAI;GAE1E,oBAAC,OAAD,YACE,qBAAC,QAAD;IAAQ,MAAK;IAAS,SAAQ;IAAU,MAAK;IAAK,SAAS;IAAU,UAAU,CAAC;cAAhF;KACE,oBAAC,MAAD,EAAM,WAAU,qBAAsB;;KACjC,KAAK,YAAY;KACf;OACL;GACF"}
1
+ {"version":3,"file":"loose-object-input.mjs","names":[],"sources":["../../../../src/components/defaults/adapters/loose-object-input.tsx"],"sourcesContent":["import { Plus, X } from \"lucide-react\";\nimport type { FieldHandle } from \"../../../types/field-handle.js\";\nimport { FieldLegend } from \"../../internal/field-legend.js\";\nimport { LiquidEditor } from \"../../internal/LiquidEditor/LiquidEditor.js\";\nimport { Button } from \"../../ui/button.js\";\nimport { Input } from \"../../ui/input.js\";\n\n/**\n * Adapter for `pipesLooseObjectInput`. The form value is a plain\n * `Record<string, string>`; each entry renders as a row. The key is the\n * object key, so it's a literal text input (committed on blur, which is when\n * the row's React key — the object key — changes). The value cell uses\n * `LiquidEditor` so it supports `/` references (input fields + secrets +\n * constants). Empty and duplicate keys aren't meaningful for an object and\n * aren't supported; `maxKeys` bounds the number of entries.\n *\n * The per-cell legend would otherwise render once per value cell — too noisy.\n * The value editors run with `hideLegend`; a single legend renders below the\n * list.\n */\nexport function LooseObjectInputAdapter(field: FieldHandle<\"loose_object_input\">) {\n const { value, setObject, searchSecrets, searchConstants, meta } = field;\n const entries = Object.entries(value);\n const maxKeys = meta.maxKeys ?? 50;\n const canAdd = entries.length < maxKeys;\n\n // Rebuild the object, renaming `oldKey`→`newKey` in place (order preserved).\n const renameKey = (oldKey: string, newKey: string) => {\n if (newKey === oldKey) return;\n const next: Record<string, string> = {};\n for (const [k, v] of Object.entries(value)) next[k === oldKey ? newKey : k] = v;\n setObject(next);\n };\n const setEntryValue = (key: string, v: string) => setObject({ ...value, [key]: v });\n const removeKey = (key: string) => {\n const { [key]: _removed, ...rest } = value;\n setObject(rest);\n };\n // One blank slot at a time — fill its key before adding another.\n const addEntry = () => {\n if (Object.hasOwn(value, \"\")) return;\n setObject({ ...value, \"\": \"\" });\n };\n\n return (\n <div data-p0=\"input\" className=\"pz:flex pz:flex-col pz:gap-2\">\n {entries.length === 0 && (\n <p className=\"pz:text-xs pz:text-muted-foreground\">\n {meta.keyLabel ? `No ${meta.keyLabel.toLowerCase()}s yet.` : \"No entries yet.\"}\n </p>\n )}\n {entries.map(([key, val]) => (\n <div key={key} className=\"pz:flex pz:items-start pz:gap-2\">\n {/* shrink-0: a long value must wrap, not squeeze the key input. */}\n <div className=\"pz:basis-1/3 pz:shrink-0\">\n <Input\n defaultValue={key}\n onBlur={(e) => renameKey(key, e.target.value)}\n placeholder={meta.keyPlaceholder ?? meta.keyLabel ?? \"Key\"}\n />\n </div>\n <div className=\"pz:min-w-0 pz:flex-1 pz:wrap-anywhere pz:rounded-md pz:border pz:border-input pz:bg-transparent\">\n <LiquidEditor\n value={val}\n onChange={(v) => setEntryValue(key, v)}\n inputFields={meta.inputFields ?? []}\n searchSecrets={searchSecrets}\n searchConstants={searchConstants}\n placeholder={meta.valuePlaceholder ?? meta.valueLabel ?? \"Value\"}\n hideLegend\n />\n </div>\n <Button\n type=\"button\"\n variant=\"ghost\"\n size=\"icon\"\n aria-label=\"Remove row\"\n onClick={() => removeKey(key)}\n >\n <X className=\"pz:size-4\" />\n </Button>\n </div>\n ))}\n {entries.length > 0 && (\n <FieldLegend entries={[{ key: \"/\", label: \"to insert a reference\" }]} />\n )}\n <div>\n <Button type=\"button\" variant=\"outline\" size=\"sm\" onClick={addEntry} disabled={!canAdd}>\n <Plus className=\"pz:size-4 pz:mr-1\" />\n Add {meta.keyLabel ?? \"row\"}\n </Button>\n </div>\n </div>\n );\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;AAoBA,SAAgB,wBAAwB,OAA0C;CAChF,MAAM,EAAE,OAAO,WAAW,eAAe,iBAAiB,SAAS;CACnE,MAAM,UAAU,OAAO,QAAQ,MAAM;CACrC,MAAM,UAAU,KAAK,WAAW;CAChC,MAAM,SAAS,QAAQ,SAAS;CAGhC,MAAM,aAAa,QAAgB,WAAmB;AACpD,MAAI,WAAW,OAAQ;EACvB,MAAM,OAA+B,EAAE;AACvC,OAAK,MAAM,CAAC,GAAG,MAAM,OAAO,QAAQ,MAAM,CAAE,MAAK,MAAM,SAAS,SAAS,KAAK;AAC9E,YAAU,KAAK;;CAEjB,MAAM,iBAAiB,KAAa,MAAc,UAAU;EAAE,GAAG;GAAQ,MAAM;EAAG,CAAC;CACnF,MAAM,aAAa,QAAgB;EACjC,MAAM,GAAG,MAAM,UAAU,GAAG,SAAS;AACrC,YAAU,KAAK;;CAGjB,MAAM,iBAAiB;AACrB,MAAI,OAAO,OAAO,OAAO,GAAG,CAAE;AAC9B,YAAU;GAAE,GAAG;GAAO,IAAI;GAAI,CAAC;;AAGjC,QACE,qBAAC,OAAD;EAAK,WAAQ;EAAQ,WAAU;YAA/B;GACG,QAAQ,WAAW,KAClB,oBAAC,KAAD;IAAG,WAAU;cACV,KAAK,WAAW,MAAM,KAAK,SAAS,aAAa,CAAC,UAAU;IAC3D;GAEL,QAAQ,KAAK,CAAC,KAAK,SAClB,qBAAC,OAAD;IAAe,WAAU;cAAzB;KAEE,oBAAC,OAAD;MAAK,WAAU;gBACb,oBAAC,OAAD;OACE,cAAc;OACd,SAAS,MAAM,UAAU,KAAK,EAAE,OAAO,MAAM;OAC7C,aAAa,KAAK,kBAAkB,KAAK,YAAY;OACrD;MACE;KACN,oBAAC,OAAD;MAAK,WAAU;gBACb,oBAAC,cAAD;OACE,OAAO;OACP,WAAW,MAAM,cAAc,KAAK,EAAE;OACtC,aAAa,KAAK,eAAe,EAAE;OACpB;OACE;OACjB,aAAa,KAAK,oBAAoB,KAAK,cAAc;OACzD;OACA;MACE;KACN,oBAAC,QAAD;MACE,MAAK;MACL,SAAQ;MACR,MAAK;MACL,cAAW;MACX,eAAe,UAAU,IAAI;gBAE7B,oBAAC,GAAD,EAAG,WAAU,aAAc;MACpB;KACL;MA7BI,IA6BJ,CACN;GACD,QAAQ,SAAS,KAChB,oBAAC,aAAD,EAAa,SAAS,CAAC;IAAE,KAAK;IAAK,OAAO;IAAyB,CAAC,EAAI;GAE1E,oBAAC,OAAD,YACE,qBAAC,QAAD;IAAQ,MAAK;IAAS,SAAQ;IAAU,MAAK;IAAK,SAAS;IAAU,UAAU,CAAC;cAAhF;KACE,oBAAC,MAAD,EAAM,WAAU,qBAAsB;;KACjC,KAAK,YAAY;KACf;OACL;GACF"}
@@ -85,7 +85,7 @@ declare function CatalogDocsBadge({
85
85
  variant
86
86
  }: CatalogDocsBadgeProps): _$react_jsx_runtime0.JSX.Element | null;
87
87
  interface CatalogCopyIdProps {
88
- /** Override the auto-bound id. Defaults to `card.pipeId` / `card.searchId` / `card.searchesId`. */
88
+ /** Override the auto-bound id. Defaults to `card.pipeId` / `card.searchId`. */
89
89
  value?: string;
90
90
  className?: string;
91
91
  }
@@ -168,7 +168,6 @@ function CatalogCopyId({ value, className }) {
168
168
  function deriveCardId(card) {
169
169
  if (!card) return void 0;
170
170
  if ("pipeId" in card) return card.pipeId;
171
- if ("searchesId" in card) return card.searchesId;
172
171
  if ("searchId" in card) return card.searchId;
173
172
  if ("effectId" in card) return card.effectId;
174
173
  }
@@ -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\" | \"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
+ {"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`. */\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 (\"searchId\" in card) return card.searchId;\n if (\"effectId\" in card) return card.effectId;\n return undefined;\n}\n"],"mappings":"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"}
@@ -13,8 +13,8 @@ interface CatalogCardProps extends ComponentProps<"div"> {
13
13
  * consumers can override paddings/colors/borders via `classNames.card` or
14
14
  * `className` without fighting the cascade.
15
15
  *
16
- * Most consumers use `<PipeCatalogCard>` / `<SearchCatalogCard>` /
17
- * `<SearchesCatalogCard>` instead, which provides the card context for
16
+ * Most consumers use `<PipeCatalogCard>` / `<SearchCatalogCard>` instead,
17
+ * which provides the card context for
18
18
  * self-binding child primitives.
19
19
  */
20
20
  declare function CatalogCard({
@@ -13,8 +13,8 @@ import { jsx } from "react/jsx-runtime";
13
13
  * consumers can override paddings/colors/borders via `classNames.card` or
14
14
  * `className` without fighting the cascade.
15
15
  *
16
- * Most consumers use `<PipeCatalogCard>` / `<SearchCatalogCard>` /
17
- * `<SearchesCatalogCard>` instead, which provides the card context for
16
+ * Most consumers use `<PipeCatalogCard>` / `<SearchCatalogCard>` instead,
17
+ * which provides the card context for
18
18
  * self-binding child primitives.
19
19
  */
20
20
  function CatalogCard({ className, onClick, children, ...rest }) {
@@ -1 +1 @@
1
- {"version":3,"file":"card-primitives.mjs","names":[],"sources":["../../../../src/components/defaults/catalog/card-primitives.tsx"],"sourcesContent":["import { mergeProps } from \"@base-ui/react/merge-props\";\nimport { useRender } from \"@base-ui/react/use-render\";\nimport { Children, type ComponentProps, type MouseEvent } from \"react\";\nimport { useAnyCatalogCardOptional } from \"../../../context/catalog-card-context.js\";\nimport { useCatalogConfig } from \"../../../context/catalog-config-context.js\";\nimport { cn } from \"../../../lib/utils.js\";\nimport { Button } from \"../../ui/button.js\";\n\n/* -------------------------------------------------------------------------- */\n/* Card root */\n/* -------------------------------------------------------------------------- */\n\nexport interface CatalogCardProps extends ComponentProps<\"div\"> {\n onClick?: (e: MouseEvent<HTMLDivElement>) => void;\n}\n\n/**\n * Bare flat card container. Defaults are structural only (flex column) so\n * consumers can override paddings/colors/borders via `classNames.card` or\n * `className` without fighting the cascade.\n *\n * Most consumers use `<PipeCatalogCard>` / `<SearchCatalogCard>` /\n * `<SearchesCatalogCard>` instead, which provides the card context for\n * self-binding child primitives.\n */\nexport function CatalogCard({ className, onClick, children, ...rest }: CatalogCardProps) {\n const { classNames } = useCatalogConfig();\n const interactive = !!onClick;\n return (\n <div\n data-p0=\"catalog-card\"\n role={interactive ? \"button\" : undefined}\n tabIndex={interactive ? 0 : undefined}\n onClick={onClick}\n onKeyDown={\n interactive\n ? (e) => {\n if (e.key === \"Enter\" || e.key === \" \") {\n e.preventDefault();\n onClick?.(e as unknown as MouseEvent<HTMLDivElement>);\n }\n }\n : undefined\n }\n className={cn(\"pz:flex pz:flex-col\", classNames?.card, className)}\n {...rest}\n >\n {children}\n </div>\n );\n}\n\n/* -------------------------------------------------------------------------- */\n/* Card header */\n/* -------------------------------------------------------------------------- */\n\nexport type CatalogCardHeaderState = {};\n\nexport interface CatalogCardHeaderProps\n extends useRender.ComponentProps<\"div\", CatalogCardHeaderState> {}\n\nexport function CatalogCardHeader({ render, className, ...props }: CatalogCardHeaderProps) {\n const { classNames } = useCatalogConfig();\n return useRender({\n defaultTagName: \"div\",\n render,\n state: {} as CatalogCardHeaderState,\n props: mergeProps<\"div\">(\n {\n className: cn(\"pz:flex pz:items-start pz:gap-2\", classNames?.cardHeader, className),\n ...({ \"data-p0\": \"catalog-card-header\" } as Record<string, string>),\n },\n props,\n ),\n });\n}\n\n/* -------------------------------------------------------------------------- */\n/* Card title — self-binds to card.label */\n/* -------------------------------------------------------------------------- */\n\nexport interface CatalogCardTitleState {\n label: string;\n}\n\nexport interface CatalogCardTitleProps\n extends useRender.ComponentProps<\"h3\", CatalogCardTitleState> {}\n\nexport function CatalogCardTitle({ children, render, className, ...props }: CatalogCardTitleProps) {\n const { classNames } = useCatalogConfig();\n const card = useAnyCatalogCardOptional()?.card;\n const label = (card?.label ?? \"\") as string;\n return useRender({\n defaultTagName: \"h3\",\n render,\n state: { label },\n props: mergeProps<\"h3\">(\n {\n className: cn(\n \"pz:text-sm pz:font-semibold pz:leading-tight pz:m-0 pz:line-clamp-2 pz:flex-1\",\n classNames?.cardLabel,\n className,\n ),\n children: children ?? label,\n ...({ \"data-p0\": \"catalog-card-title\" } as Record<string, string>),\n },\n props,\n ),\n });\n}\n\n/* -------------------------------------------------------------------------- */\n/* Card description — self-binds to card.description */\n/* -------------------------------------------------------------------------- */\n\nexport interface CatalogCardDescriptionState {\n description: string;\n}\n\nexport interface CatalogCardDescriptionProps\n extends useRender.ComponentProps<\"p\", CatalogCardDescriptionState> {}\n\nexport function CatalogCardDescription({\n children,\n render,\n className,\n ...props\n}: CatalogCardDescriptionProps) {\n const { classNames } = useCatalogConfig();\n const card = useAnyCatalogCardOptional()?.card;\n const description = (card?.description ?? \"\") as string;\n return useRender({\n defaultTagName: \"p\",\n render,\n state: { description },\n props: mergeProps<\"p\">(\n {\n className: cn(\n \"pz:text-xs pz:text-muted-foreground pz:m-0 pz:line-clamp-2\",\n classNames?.cardDescription,\n className,\n ),\n children: children ?? description,\n ...({ \"data-p0\": \"catalog-card-description\" } as Record<string, string>),\n },\n props,\n ),\n });\n}\n\n/* -------------------------------------------------------------------------- */\n/* Card badges row + single badge button */\n/* -------------------------------------------------------------------------- */\n\nexport interface CatalogCardBadgesProps extends ComponentProps<\"div\"> {}\n\nexport function CatalogCardBadges({ className, children, ...rest }: CatalogCardBadgesProps) {\n const { classNames } = useCatalogConfig();\n const visible = Children.toArray(children);\n if (visible.length === 0) return null;\n return (\n <div\n data-p0=\"catalog-card-badges\"\n className={cn(\n \"pz:flex pz:flex-wrap pz:gap-1.5 pz:items-center\",\n classNames?.cardBadges,\n className,\n )}\n onClick={(e) => e.stopPropagation()}\n {...rest}\n >\n {visible}\n </div>\n );\n}\n\nexport interface CatalogCardBadgeProps extends Omit<ComponentProps<typeof Button>, \"size\"> {\n size?: \"xs\" | \"sm\";\n}\n\nexport function CatalogCardBadge({\n className,\n variant = \"outline\",\n size = \"xs\",\n onClick,\n ...rest\n}: CatalogCardBadgeProps) {\n const { classNames } = useCatalogConfig();\n return (\n <Button\n data-p0=\"catalog-card-badge\"\n variant={variant}\n size={size}\n className={cn(classNames?.badge, className)}\n onClick={(e) => {\n e.stopPropagation();\n onClick?.(e);\n }}\n {...rest}\n />\n );\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;AAyBA,SAAgB,YAAY,EAAE,WAAW,SAAS,UAAU,GAAG,QAA0B;CACvF,MAAM,EAAE,eAAe,kBAAkB;CACzC,MAAM,cAAc,CAAC,CAAC;AACtB,QACE,oBAAC,OAAD;EACE,WAAQ;EACR,MAAM,cAAc,WAAW;EAC/B,UAAU,cAAc,IAAI;EACnB;EACT,WACE,eACK,MAAM;AACL,OAAI,EAAE,QAAQ,WAAW,EAAE,QAAQ,KAAK;AACtC,MAAE,gBAAgB;AAClB,cAAU,EAA2C;;MAGzD;EAEN,WAAW,GAAG,uBAAuB,YAAY,MAAM,UAAU;EACjE,GAAI;EAEH;EACG;;AAaV,SAAgB,kBAAkB,EAAE,QAAQ,WAAW,GAAG,SAAiC;CACzF,MAAM,EAAE,eAAe,kBAAkB;AACzC,QAAO,UAAU;EACf,gBAAgB;EAChB;EACA,OAAO,EAAE;EACT,OAAO,WACL;GACE,WAAW,GAAG,mCAAmC,YAAY,YAAY,UAAU;GAC7E,WAAW;GAClB,EACD,MACD;EACF,CAAC;;AAcJ,SAAgB,iBAAiB,EAAE,UAAU,QAAQ,WAAW,GAAG,SAAgC;CACjG,MAAM,EAAE,eAAe,kBAAkB;CAEzC,MAAM,SADO,2BAA2B,EAAE,OACrB,SAAS;AAC9B,QAAO,UAAU;EACf,gBAAgB;EAChB;EACA,OAAO,EAAE,OAAO;EAChB,OAAO,WACL;GACE,WAAW,GACT,iFACA,YAAY,WACZ,UACD;GACD,UAAU,YAAY;GAChB,WAAW;GAClB,EACD,MACD;EACF,CAAC;;AAcJ,SAAgB,uBAAuB,EACrC,UACA,QACA,WACA,GAAG,SAC2B;CAC9B,MAAM,EAAE,eAAe,kBAAkB;CAEzC,MAAM,eADO,2BAA2B,EAAE,OACf,eAAe;AAC1C,QAAO,UAAU;EACf,gBAAgB;EAChB;EACA,OAAO,EAAE,aAAa;EACtB,OAAO,WACL;GACE,WAAW,GACT,8DACA,YAAY,iBACZ,UACD;GACD,UAAU,YAAY;GAChB,WAAW;GAClB,EACD,MACD;EACF,CAAC;;AASJ,SAAgB,kBAAkB,EAAE,WAAW,UAAU,GAAG,QAAgC;CAC1F,MAAM,EAAE,eAAe,kBAAkB;CACzC,MAAM,UAAU,SAAS,QAAQ,SAAS;AAC1C,KAAI,QAAQ,WAAW,EAAG,QAAO;AACjC,QACE,oBAAC,OAAD;EACE,WAAQ;EACR,WAAW,GACT,mDACA,YAAY,YACZ,UACD;EACD,UAAU,MAAM,EAAE,iBAAiB;EACnC,GAAI;YAEH;EACG;;AAQV,SAAgB,iBAAiB,EAC/B,WACA,UAAU,WACV,OAAO,MACP,SACA,GAAG,QACqB;CACxB,MAAM,EAAE,eAAe,kBAAkB;AACzC,QACE,oBAAC,QAAD;EACE,WAAQ;EACC;EACH;EACN,WAAW,GAAG,YAAY,OAAO,UAAU;EAC3C,UAAU,MAAM;AACd,KAAE,iBAAiB;AACnB,aAAU,EAAE;;EAEd,GAAI;EACJ"}
1
+ {"version":3,"file":"card-primitives.mjs","names":[],"sources":["../../../../src/components/defaults/catalog/card-primitives.tsx"],"sourcesContent":["import { mergeProps } from \"@base-ui/react/merge-props\";\nimport { useRender } from \"@base-ui/react/use-render\";\nimport { Children, type ComponentProps, type MouseEvent } from \"react\";\nimport { useAnyCatalogCardOptional } from \"../../../context/catalog-card-context.js\";\nimport { useCatalogConfig } from \"../../../context/catalog-config-context.js\";\nimport { cn } from \"../../../lib/utils.js\";\nimport { Button } from \"../../ui/button.js\";\n\n/* -------------------------------------------------------------------------- */\n/* Card root */\n/* -------------------------------------------------------------------------- */\n\nexport interface CatalogCardProps extends ComponentProps<\"div\"> {\n onClick?: (e: MouseEvent<HTMLDivElement>) => void;\n}\n\n/**\n * Bare flat card container. Defaults are structural only (flex column) so\n * consumers can override paddings/colors/borders via `classNames.card` or\n * `className` without fighting the cascade.\n *\n * Most consumers use `<PipeCatalogCard>` / `<SearchCatalogCard>` instead,\n * which provides the card context for\n * self-binding child primitives.\n */\nexport function CatalogCard({ className, onClick, children, ...rest }: CatalogCardProps) {\n const { classNames } = useCatalogConfig();\n const interactive = !!onClick;\n return (\n <div\n data-p0=\"catalog-card\"\n role={interactive ? \"button\" : undefined}\n tabIndex={interactive ? 0 : undefined}\n onClick={onClick}\n onKeyDown={\n interactive\n ? (e) => {\n if (e.key === \"Enter\" || e.key === \" \") {\n e.preventDefault();\n onClick?.(e as unknown as MouseEvent<HTMLDivElement>);\n }\n }\n : undefined\n }\n className={cn(\"pz:flex pz:flex-col\", classNames?.card, className)}\n {...rest}\n >\n {children}\n </div>\n );\n}\n\n/* -------------------------------------------------------------------------- */\n/* Card header */\n/* -------------------------------------------------------------------------- */\n\nexport type CatalogCardHeaderState = {};\n\nexport interface CatalogCardHeaderProps\n extends useRender.ComponentProps<\"div\", CatalogCardHeaderState> {}\n\nexport function CatalogCardHeader({ render, className, ...props }: CatalogCardHeaderProps) {\n const { classNames } = useCatalogConfig();\n return useRender({\n defaultTagName: \"div\",\n render,\n state: {} as CatalogCardHeaderState,\n props: mergeProps<\"div\">(\n {\n className: cn(\"pz:flex pz:items-start pz:gap-2\", classNames?.cardHeader, className),\n ...({ \"data-p0\": \"catalog-card-header\" } as Record<string, string>),\n },\n props,\n ),\n });\n}\n\n/* -------------------------------------------------------------------------- */\n/* Card title — self-binds to card.label */\n/* -------------------------------------------------------------------------- */\n\nexport interface CatalogCardTitleState {\n label: string;\n}\n\nexport interface CatalogCardTitleProps\n extends useRender.ComponentProps<\"h3\", CatalogCardTitleState> {}\n\nexport function CatalogCardTitle({ children, render, className, ...props }: CatalogCardTitleProps) {\n const { classNames } = useCatalogConfig();\n const card = useAnyCatalogCardOptional()?.card;\n const label = (card?.label ?? \"\") as string;\n return useRender({\n defaultTagName: \"h3\",\n render,\n state: { label },\n props: mergeProps<\"h3\">(\n {\n className: cn(\n \"pz:text-sm pz:font-semibold pz:leading-tight pz:m-0 pz:line-clamp-2 pz:flex-1\",\n classNames?.cardLabel,\n className,\n ),\n children: children ?? label,\n ...({ \"data-p0\": \"catalog-card-title\" } as Record<string, string>),\n },\n props,\n ),\n });\n}\n\n/* -------------------------------------------------------------------------- */\n/* Card description — self-binds to card.description */\n/* -------------------------------------------------------------------------- */\n\nexport interface CatalogCardDescriptionState {\n description: string;\n}\n\nexport interface CatalogCardDescriptionProps\n extends useRender.ComponentProps<\"p\", CatalogCardDescriptionState> {}\n\nexport function CatalogCardDescription({\n children,\n render,\n className,\n ...props\n}: CatalogCardDescriptionProps) {\n const { classNames } = useCatalogConfig();\n const card = useAnyCatalogCardOptional()?.card;\n const description = (card?.description ?? \"\") as string;\n return useRender({\n defaultTagName: \"p\",\n render,\n state: { description },\n props: mergeProps<\"p\">(\n {\n className: cn(\n \"pz:text-xs pz:text-muted-foreground pz:m-0 pz:line-clamp-2\",\n classNames?.cardDescription,\n className,\n ),\n children: children ?? description,\n ...({ \"data-p0\": \"catalog-card-description\" } as Record<string, string>),\n },\n props,\n ),\n });\n}\n\n/* -------------------------------------------------------------------------- */\n/* Card badges row + single badge button */\n/* -------------------------------------------------------------------------- */\n\nexport interface CatalogCardBadgesProps extends ComponentProps<\"div\"> {}\n\nexport function CatalogCardBadges({ className, children, ...rest }: CatalogCardBadgesProps) {\n const { classNames } = useCatalogConfig();\n const visible = Children.toArray(children);\n if (visible.length === 0) return null;\n return (\n <div\n data-p0=\"catalog-card-badges\"\n className={cn(\n \"pz:flex pz:flex-wrap pz:gap-1.5 pz:items-center\",\n classNames?.cardBadges,\n className,\n )}\n onClick={(e) => e.stopPropagation()}\n {...rest}\n >\n {visible}\n </div>\n );\n}\n\nexport interface CatalogCardBadgeProps extends Omit<ComponentProps<typeof Button>, \"size\"> {\n size?: \"xs\" | \"sm\";\n}\n\nexport function CatalogCardBadge({\n className,\n variant = \"outline\",\n size = \"xs\",\n onClick,\n ...rest\n}: CatalogCardBadgeProps) {\n const { classNames } = useCatalogConfig();\n return (\n <Button\n data-p0=\"catalog-card-badge\"\n variant={variant}\n size={size}\n className={cn(classNames?.badge, className)}\n onClick={(e) => {\n e.stopPropagation();\n onClick?.(e);\n }}\n {...rest}\n />\n );\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;AAyBA,SAAgB,YAAY,EAAE,WAAW,SAAS,UAAU,GAAG,QAA0B;CACvF,MAAM,EAAE,eAAe,kBAAkB;CACzC,MAAM,cAAc,CAAC,CAAC;AACtB,QACE,oBAAC,OAAD;EACE,WAAQ;EACR,MAAM,cAAc,WAAW;EAC/B,UAAU,cAAc,IAAI;EACnB;EACT,WACE,eACK,MAAM;AACL,OAAI,EAAE,QAAQ,WAAW,EAAE,QAAQ,KAAK;AACtC,MAAE,gBAAgB;AAClB,cAAU,EAA2C;;MAGzD;EAEN,WAAW,GAAG,uBAAuB,YAAY,MAAM,UAAU;EACjE,GAAI;EAEH;EACG;;AAaV,SAAgB,kBAAkB,EAAE,QAAQ,WAAW,GAAG,SAAiC;CACzF,MAAM,EAAE,eAAe,kBAAkB;AACzC,QAAO,UAAU;EACf,gBAAgB;EAChB;EACA,OAAO,EAAE;EACT,OAAO,WACL;GACE,WAAW,GAAG,mCAAmC,YAAY,YAAY,UAAU;GAC7E,WAAW;GAClB,EACD,MACD;EACF,CAAC;;AAcJ,SAAgB,iBAAiB,EAAE,UAAU,QAAQ,WAAW,GAAG,SAAgC;CACjG,MAAM,EAAE,eAAe,kBAAkB;CAEzC,MAAM,SADO,2BAA2B,EAAE,OACrB,SAAS;AAC9B,QAAO,UAAU;EACf,gBAAgB;EAChB;EACA,OAAO,EAAE,OAAO;EAChB,OAAO,WACL;GACE,WAAW,GACT,iFACA,YAAY,WACZ,UACD;GACD,UAAU,YAAY;GAChB,WAAW;GAClB,EACD,MACD;EACF,CAAC;;AAcJ,SAAgB,uBAAuB,EACrC,UACA,QACA,WACA,GAAG,SAC2B;CAC9B,MAAM,EAAE,eAAe,kBAAkB;CAEzC,MAAM,eADO,2BAA2B,EAAE,OACf,eAAe;AAC1C,QAAO,UAAU;EACf,gBAAgB;EAChB;EACA,OAAO,EAAE,aAAa;EACtB,OAAO,WACL;GACE,WAAW,GACT,8DACA,YAAY,iBACZ,UACD;GACD,UAAU,YAAY;GAChB,WAAW;GAClB,EACD,MACD;EACF,CAAC;;AASJ,SAAgB,kBAAkB,EAAE,WAAW,UAAU,GAAG,QAAgC;CAC1F,MAAM,EAAE,eAAe,kBAAkB;CACzC,MAAM,UAAU,SAAS,QAAQ,SAAS;AAC1C,KAAI,QAAQ,WAAW,EAAG,QAAO;AACjC,QACE,oBAAC,OAAD;EACE,WAAQ;EACR,WAAW,GACT,mDACA,YAAY,YACZ,UACD;EACD,UAAU,MAAM,EAAE,iBAAiB;EACnC,GAAI;YAEH;EACG;;AAQV,SAAgB,iBAAiB,EAC/B,WACA,UAAU,WACV,OAAO,MACP,SACA,GAAG,QACqB;CACxB,MAAM,EAAE,eAAe,kBAAkB;AACzC,QACE,oBAAC,QAAD;EACE,WAAQ;EACC;EACH;EACN,WAAW,GAAG,YAAY,OAAO,UAAU;EAC3C,UAAU,MAAM;AACd,KAAE,iBAAiB;AACnB,aAAU,EAAE;;EAEd,GAAI;EACJ"}
@@ -4,6 +4,7 @@ import { Switch } from "../../ui/switch.mjs";
4
4
  import { useFloatingElement } from "../../../hooks/use-floating-element.mjs";
5
5
  import { useEffect, useId, useMemo, useRef, useState } from "react";
6
6
  import { Fragment as Fragment$1, jsx, jsxs } from "react/jsx-runtime";
7
+ import { TYPES_TO_FORMATS } from "@pipe0/base";
7
8
  import { Trash2 } from "lucide-react";
8
9
  import { offset, shift } from "@floating-ui/react";
9
10
 
@@ -11,14 +12,43 @@ import { offset, shift } from "@floating-ui/react";
11
12
  const SIMPLE_FIELD_RE = /^\{\{\s*([a-zA-Z_][a-zA-Z0-9_.]*)\s*(\|\s*default:\s*"")?\s*\}\}$/;
12
13
  const SECRET_RE = /^\{\{\s*SECRETS\.([A-Z][A-Z0-9_]*)\s*\}\}$/;
13
14
  const CONSTANT_RE = /^\{\{\s*CONSTANTS\.([A-Z][A-Z0-9_]*)\s*\}\}$/;
14
- const OUTPUT_BLOCK_RE = /^\{%\s*output\s+([A-Za-z_][A-Za-z0-9_]*)\s*,\s*type:\s*"(string|number|boolean|json|unknown)"\s*(?:,\s*schema:\s*"([^"]*)")?\s*(?:,\s*description:\s*"((?:[^"\\]|\\.)*)")?\s*%\}$/;
15
+ const OUTPUT_BLOCK_RE = /^\{%\s*output\s+([A-Za-z_][A-Za-z0-9_]*)\s*((?:,\s*[a-z_]+:\s*(?:"(?:[^"\\]|\\.)*"|true|false)\s*)*)%\}$/;
16
+ const OUTPUT_ARG_RE = /([a-z_]+):\s*("(?:[^"\\]|\\.)*"|true|false)/g;
17
+ const OUTPUT_KEYS = new Set([
18
+ "type",
19
+ "schema",
20
+ "description",
21
+ "format",
22
+ "required"
23
+ ]);
24
+ function parseOutputBlock(raw) {
25
+ const m = raw.match(OUTPUT_BLOCK_RE);
26
+ if (!m) return null;
27
+ const args = {};
28
+ for (const [, key, value] of (m[2] ?? "").matchAll(OUTPUT_ARG_RE)) {
29
+ if (!key || !value || !OUTPUT_KEYS.has(key)) return null;
30
+ args[key] = value === "true" || value === "false" ? value === "true" : value.slice(1, -1).replace(/\\"/g, "\"").replace(/\\\\/g, "\\");
31
+ }
32
+ const type = args.type;
33
+ if (typeof type !== "string" || !(type in TYPES_TO_FORMATS)) return null;
34
+ const format = args.format;
35
+ if (typeof format === "string" && type !== "json" && !TYPES_TO_FORMATS[type].includes(format)) return null;
36
+ return {
37
+ name: m[1] ?? "",
38
+ type,
39
+ schema: typeof args.schema === "string" ? args.schema : "",
40
+ description: typeof args.description === "string" ? args.description : "",
41
+ format: typeof args.format === "string" ? args.format : "",
42
+ required: typeof args.required === "boolean" ? args.required : void 0
43
+ };
44
+ }
15
45
  /**
16
46
  * Contextual popover anchored to a chip's DOM rect. Different content per
17
47
  * chip kind:
18
48
  * - field: switch for `| default: ""` (simple cases only), remove.
19
49
  * - secret: publicId header, manage/remove buttons. Power users still
20
50
  * edit by hand.
21
- * - block (output declaration): name / type / description editors.
51
+ * - block (output declaration): name / type / format / description editors.
22
52
  *
23
53
  * On any mutation, the popover dispatches a single replaceWith transaction
24
54
  * over the chip's range, then closes itself. The Liquid serialization
@@ -196,26 +226,19 @@ function ConstantChipBody({ raw, remove }) {
196
226
  })] });
197
227
  }
198
228
  function BlockChipBody({ raw, replaceWith, remove }) {
199
- const initial = useMemo(() => {
200
- const m = raw.match(OUTPUT_BLOCK_RE);
201
- if (!m) return null;
202
- const [, name, type, schema, description] = m;
203
- return {
204
- name,
205
- type,
206
- schema: schema ?? "",
207
- description: description ? description.replace(/\\"/g, "\"").replace(/\\\\/g, "\\") : ""
208
- };
209
- }, [raw]);
229
+ const initial = useMemo(() => parseOutputBlock(raw), [raw]);
210
230
  const [name, setName] = useState(initial?.name ?? "");
211
231
  const [type, setType] = useState(initial?.type ?? "string");
212
232
  const [schema, setSchema] = useState(initial?.schema ?? "");
213
233
  const [description, setDescription] = useState(initial?.description ?? "");
234
+ const [format, setFormat] = useState(initial?.format ?? "");
235
+ const formatOptions = TYPES_TO_FORMATS[type];
214
236
  const idPrefix = useId();
215
237
  const nameId = `${idPrefix}-name`;
216
238
  const typeId = `${idPrefix}-type`;
217
239
  const schemaId = `${idPrefix}-schema`;
218
240
  const descId = `${idPrefix}-desc`;
241
+ const formatId = `${idPrefix}-format`;
219
242
  if (!initial) return /* @__PURE__ */ jsxs(Fragment$1, { children: [
220
243
  /* @__PURE__ */ jsx("header", {
221
244
  className: "pz:text-xs pz:font-medium pz:text-muted-foreground",
@@ -242,7 +265,9 @@ function BlockChipBody({ raw, replaceWith, remove }) {
242
265
  const escaped = description.replace(/\\/g, "\\\\").replace(/"/g, "\\\"");
243
266
  const parts = [`{% output ${name.trim()}`, `type: "${type}"`];
244
267
  if (type === "json" && schema.trim()) parts.push(`schema: "${schema.trim()}"`);
268
+ if (format && formatOptions.includes(format)) parts.push(`format: "${format}"`);
245
269
  parts.push(`description: "${escaped}"`);
270
+ if (initial?.required !== void 0) parts.push(`required: ${initial.required}`);
246
271
  replaceWith(`${parts.join(", ")} %}`);
247
272
  }
248
273
  return /* @__PURE__ */ jsxs(Fragment$1, { children: [
@@ -266,7 +291,11 @@ function BlockChipBody({ raw, replaceWith, remove }) {
266
291
  children: [/* @__PURE__ */ jsx("span", { children: "Type" }), /* @__PURE__ */ jsxs("select", {
267
292
  id: typeId,
268
293
  value: type,
269
- onChange: (e) => setType(e.target.value),
294
+ onChange: (e) => {
295
+ const next = e.target.value;
296
+ setType(next);
297
+ if (!TYPES_TO_FORMATS[next].includes(format)) setFormat("");
298
+ },
270
299
  className: "pz:rounded-sm pz:border pz:border-input pz:bg-transparent pz:px-2 pz:py-1 pz:text-sm",
271
300
  children: [
272
301
  /* @__PURE__ */ jsx("option", {
@@ -302,6 +331,23 @@ function BlockChipBody({ raw, replaceWith, remove }) {
302
331
  placeholder: "SCHEMA_NAME"
303
332
  })]
304
333
  }),
334
+ type !== "json" && formatOptions.length > 0 && /* @__PURE__ */ jsxs("label", {
335
+ htmlFor: formatId,
336
+ className: "pz:flex pz:flex-col pz:gap-1 pz:text-xs",
337
+ children: [/* @__PURE__ */ jsx("span", { children: "Format" }), /* @__PURE__ */ jsxs("select", {
338
+ id: formatId,
339
+ value: format,
340
+ onChange: (e) => setFormat(e.target.value),
341
+ className: "pz:rounded-sm pz:border pz:border-input pz:bg-transparent pz:px-2 pz:py-1 pz:text-sm",
342
+ children: [/* @__PURE__ */ jsx("option", {
343
+ value: "",
344
+ children: "none"
345
+ }), formatOptions.map((f) => /* @__PURE__ */ jsx("option", {
346
+ value: f,
347
+ children: f
348
+ }, f))]
349
+ })]
350
+ }),
305
351
  /* @__PURE__ */ jsxs("label", {
306
352
  htmlFor: descId,
307
353
  className: "pz:flex pz:flex-col pz:gap-1 pz:text-xs",
@@ -1 +1 @@
1
- {"version":3,"file":"ChipEditPopover.mjs","names":[],"sources":["../../../../src/components/internal/LiquidEditor/ChipEditPopover.tsx"],"sourcesContent":["import { offset, shift } from \"@floating-ui/react\";\nimport type { Editor } from \"@tiptap/react\";\nimport { Trash2 } from \"lucide-react\";\nimport { useEffect, useId, useMemo, useRef, useState } from \"react\";\nimport { useFloatingElement } from \"../../../hooks/use-floating-element.js\";\nimport { Button } from \"../../ui/button.js\";\nimport { Input } from \"../../ui/input.js\";\nimport { Switch } from \"../../ui/switch.js\";\nimport type { ChipKind } from \"../tag-chip-decoration.js\";\n\nconst SIMPLE_FIELD_RE = /^\\{\\{\\s*([a-zA-Z_][a-zA-Z0-9_.]*)\\s*(\\|\\s*default:\\s*\"\")?\\s*\\}\\}$/;\nconst SECRET_RE = /^\\{\\{\\s*SECRETS\\.([A-Z][A-Z0-9_]*)\\s*\\}\\}$/;\nconst CONSTANT_RE = /^\\{\\{\\s*CONSTANTS\\.([A-Z][A-Z0-9_]*)\\s*\\}\\}$/;\n// Captures `name`, `type` (string|number|boolean|json|unknown), and `description`\n// from `{% output NAME, type: \"TYPE\", description: \"...\" %}` or with a `schema:`\n// arg between type and description for json. Tolerates whitespace and ordering.\nconst OUTPUT_BLOCK_RE =\n /^\\{%\\s*output\\s+([A-Za-z_][A-Za-z0-9_]*)\\s*,\\s*type:\\s*\"(string|number|boolean|json|unknown)\"\\s*(?:,\\s*schema:\\s*\"([^\"]*)\")?\\s*(?:,\\s*description:\\s*\"((?:[^\"\\\\]|\\\\.)*)\")?\\s*%\\}$/;\n\nexport interface ChipEditTarget {\n kind: ChipKind;\n raw: string;\n from: number;\n to: number;\n rect: DOMRect;\n}\n\n/**\n * Contextual popover anchored to a chip's DOM rect. Different content per\n * chip kind:\n * - field: switch for `| default: \"\"` (simple cases only), remove.\n * - secret: publicId header, manage/remove buttons. Power users still\n * edit by hand.\n * - block (output declaration): name / type / description editors.\n *\n * On any mutation, the popover dispatches a single replaceWith transaction\n * over the chip's range, then closes itself. The Liquid serialization\n * stays identical to what would have been authored by hand.\n */\nexport function ChipEditPopover({\n editor,\n target,\n onClose,\n}: {\n editor: Editor;\n target: ChipEditTarget;\n onClose: () => void;\n}) {\n const { ref, style, isMounted, getFloatingProps } = useFloatingElement(true, target.rect, 1100, {\n placement: \"bottom-start\",\n middleware: [offset(6), shift()],\n onOpenChange(open) {\n if (!open) onClose();\n },\n dismissOptions: { outsidePress: true, outsidePressEvent: \"mousedown\" },\n });\n\n const popupRef = useRef<HTMLDivElement | null>(null);\n\n useEffect(() => {\n function onKey(e: KeyboardEvent) {\n if (e.key === \"Escape\") onClose();\n }\n window.addEventListener(\"keydown\", onKey);\n return () => window.removeEventListener(\"keydown\", onKey);\n }, [onClose]);\n\n function replaceWith(next: string) {\n editor.chain().focus().insertContentAt({ from: target.from, to: target.to }, next).run();\n onClose();\n }\n\n function remove() {\n editor.chain().focus().deleteRange({ from: target.from, to: target.to }).run();\n onClose();\n }\n\n if (!isMounted) return null;\n\n return (\n <div\n ref={(el) => {\n popupRef.current = el;\n ref(el);\n }}\n style={style}\n {...getFloatingProps()}\n onMouseDown={(e) => e.stopPropagation()}\n className=\"pz:flex pz:flex-col pz:gap-2 pz:rounded-md pz:border pz:border-input pz:bg-popover pz:p-3 pz:text-popover-foreground pz:shadow-md pz:min-w-72\"\n role=\"dialog\"\n aria-label={`Edit ${target.kind} chip`}\n >\n {target.kind === \"field\" && (\n <FieldChipBody raw={target.raw} replaceWith={replaceWith} remove={remove} />\n )}\n {target.kind === \"secret\" && <SecretChipBody raw={target.raw} remove={remove} />}\n {target.kind === \"constant\" && <ConstantChipBody raw={target.raw} remove={remove} />}\n {target.kind === \"block\" && (\n <BlockChipBody raw={target.raw} replaceWith={replaceWith} remove={remove} />\n )}\n </div>\n );\n}\n\nfunction FieldChipBody({\n raw,\n replaceWith,\n remove,\n}: {\n raw: string;\n replaceWith: (next: string) => void;\n remove: () => void;\n}) {\n const match = raw.match(SIMPLE_FIELD_RE);\n const name = match?.[1];\n const allowEmpty = !!match?.[2];\n const isSimple = !!match;\n\n if (!isSimple || !name) {\n return (\n <>\n <header className=\"pz:text-xs pz:font-medium pz:text-muted-foreground\">\n Field reference (advanced)\n </header>\n <p className=\"pz:text-xs pz:text-muted-foreground\">\n This chip uses a custom Liquid filter chain. Edit the raw text in the editor to change it.\n </p>\n <pre className=\"pz:overflow-x-auto pz:rounded-sm pz:bg-muted pz:px-2 pz:py-1 pz:text-xs\">\n {raw}\n </pre>\n <Button type=\"button\" variant=\"outline\" size=\"sm\" onClick={remove}>\n <Trash2 className=\"pz:size-3.5 pz:mr-1\" />\n Remove\n </Button>\n </>\n );\n }\n\n function toggleAllowEmpty() {\n replaceWith(allowEmpty ? `{{ ${name} }}` : `{{ ${name} | default: \"\" }}`);\n }\n\n return (\n <>\n <header className=\"pz:flex pz:items-center pz:justify-between pz:gap-2\">\n <span className=\"pz:text-xs pz:font-medium pz:text-muted-foreground\">Field reference</span>\n <code className=\"pz:text-xs pz:text-sky-700\">{name}</code>\n </header>\n <div className=\"pz:flex pz:items-center pz:justify-between pz:gap-3 pz:text-sm\">\n <span className=\"pz:flex pz:flex-col\">\n <span>Allow empty</span>\n <span className=\"pz:text-xs pz:text-muted-foreground\">\n Inserts <code>| default: \"\"</code> so missing values render as empty.\n </span>\n </span>\n <Switch checked={allowEmpty} onCheckedChange={toggleAllowEmpty} />\n </div>\n <Button type=\"button\" variant=\"outline\" size=\"sm\" onClick={remove}>\n <Trash2 className=\"pz:size-3.5 pz:mr-1\" />\n Remove\n </Button>\n </>\n );\n}\n\nfunction SecretChipBody({ raw, remove }: { raw: string; remove: () => void }) {\n const publicId = raw.match(SECRET_RE)?.[1];\n\n return (\n <>\n <header className=\"pz:flex pz:items-center pz:justify-between pz:gap-2\">\n <span className=\"pz:text-xs pz:font-medium pz:text-muted-foreground\">Secret reference</span>\n <code className=\"pz:text-xs pz:text-amber-700\">{publicId ?? \"(unknown)\"}</code>\n </header>\n <Button type=\"button\" variant=\"outline\" size=\"sm\" onClick={remove}>\n <Trash2 className=\"pz:size-3.5 pz:mr-1\" />\n Remove\n </Button>\n </>\n );\n}\n\nfunction ConstantChipBody({ raw, remove }: { raw: string; remove: () => void }) {\n const publicId = raw.match(CONSTANT_RE)?.[1];\n\n return (\n <>\n <header className=\"pz:flex pz:items-center pz:justify-between pz:gap-2\">\n <span className=\"pz:text-xs pz:font-medium pz:text-muted-foreground\">\n Constant reference\n </span>\n <code className=\"pz:text-xs pz:text-emerald-700\">{publicId ?? \"(unknown)\"}</code>\n </header>\n <Button type=\"button\" variant=\"outline\" size=\"sm\" onClick={remove}>\n <Trash2 className=\"pz:size-3.5 pz:mr-1\" />\n Remove\n </Button>\n </>\n );\n}\n\nfunction BlockChipBody({\n raw,\n replaceWith,\n remove,\n}: {\n raw: string;\n replaceWith: (next: string) => void;\n remove: () => void;\n}) {\n const initial = useMemo(() => {\n const m = raw.match(OUTPUT_BLOCK_RE);\n if (!m) return null;\n const [, name, type, schema, description] = m;\n return {\n name,\n type: type as \"string\" | \"number\" | \"boolean\" | \"json\" | \"unknown\",\n schema: schema ?? \"\",\n description: description ? description.replace(/\\\\\"/g, '\"').replace(/\\\\\\\\/g, \"\\\\\") : \"\",\n };\n }, [raw]);\n\n const [name, setName] = useState(initial?.name ?? \"\");\n const [type, setType] = useState<\"string\" | \"number\" | \"boolean\" | \"json\" | \"unknown\">(\n initial?.type ?? \"string\",\n );\n const [schema, setSchema] = useState(initial?.schema ?? \"\");\n const [description, setDescription] = useState(initial?.description ?? \"\");\n const idPrefix = useId();\n const nameId = `${idPrefix}-name`;\n const typeId = `${idPrefix}-type`;\n const schemaId = `${idPrefix}-schema`;\n const descId = `${idPrefix}-desc`;\n\n if (!initial) {\n return (\n <>\n <header className=\"pz:text-xs pz:font-medium pz:text-muted-foreground\">\n Block (advanced)\n </header>\n <p className=\"pz:text-xs pz:text-muted-foreground\">\n This block uses a non-standard form. Edit the raw text in the editor.\n </p>\n <pre className=\"pz:overflow-x-auto pz:rounded-sm pz:bg-muted pz:px-2 pz:py-1 pz:text-xs\">\n {raw}\n </pre>\n <Button type=\"button\" variant=\"outline\" size=\"sm\" onClick={remove}>\n <Trash2 className=\"pz:size-3.5 pz:mr-1\" />\n Remove\n </Button>\n </>\n );\n }\n\n function save() {\n if (!name.trim()) return;\n const escaped = description.replace(/\\\\/g, \"\\\\\\\\\").replace(/\"/g, '\\\\\"');\n const parts = [`{% output ${name.trim()}`, `type: \"${type}\"`];\n if (type === \"json\" && schema.trim()) parts.push(`schema: \"${schema.trim()}\"`);\n parts.push(`description: \"${escaped}\"`);\n replaceWith(`${parts.join(\", \")} %}`);\n }\n\n return (\n <>\n <header className=\"pz:text-xs pz:font-medium pz:text-muted-foreground\">\n Output declaration\n </header>\n <label htmlFor={nameId} className=\"pz:flex pz:flex-col pz:gap-1 pz:text-xs\">\n <span>Name</span>\n <Input\n id={nameId}\n value={name}\n onChange={(e) => setName(e.target.value)}\n placeholder=\"FIELD_NAME\"\n />\n </label>\n <label htmlFor={typeId} className=\"pz:flex pz:flex-col pz:gap-1 pz:text-xs\">\n <span>Type</span>\n <select\n id={typeId}\n value={type}\n onChange={(e) =>\n setType(e.target.value as \"string\" | \"number\" | \"boolean\" | \"json\" | \"unknown\")\n }\n className=\"pz:rounded-sm pz:border pz:border-input pz:bg-transparent pz:px-2 pz:py-1 pz:text-sm\"\n >\n <option value=\"string\">string</option>\n <option value=\"number\">number</option>\n <option value=\"boolean\">boolean</option>\n <option value=\"json\">json</option>\n <option value=\"unknown\">unknown</option>\n </select>\n </label>\n {type === \"json\" && (\n <label htmlFor={schemaId} className=\"pz:flex pz:flex-col pz:gap-1 pz:text-xs\">\n <span>Schema</span>\n <Input\n id={schemaId}\n value={schema}\n onChange={(e) => setSchema(e.target.value)}\n placeholder=\"SCHEMA_NAME\"\n />\n </label>\n )}\n <label htmlFor={descId} className=\"pz:flex pz:flex-col pz:gap-1 pz:text-xs\">\n <span>Description</span>\n <Input id={descId} value={description} onChange={(e) => setDescription(e.target.value)} />\n </label>\n <div className=\"pz:flex pz:items-center pz:justify-between pz:gap-2 pz:pt-1\">\n <Button type=\"button\" variant=\"ghost\" size=\"sm\" onClick={remove}>\n <Trash2 className=\"pz:size-3.5 pz:mr-1\" />\n Remove\n </Button>\n <Button type=\"button\" size=\"sm\" onClick={save}>\n Save\n </Button>\n </div>\n </>\n );\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"ChipEditPopover.mjs","names":[],"sources":["../../../../src/components/internal/LiquidEditor/ChipEditPopover.tsx"],"sourcesContent":["import { offset, shift } from \"@floating-ui/react\";\nimport { TYPES_TO_FORMATS } from \"@pipe0/base\";\nimport type { Editor } from \"@tiptap/react\";\nimport { Trash2 } from \"lucide-react\";\nimport { useEffect, useId, useMemo, useRef, useState } from \"react\";\nimport { useFloatingElement } from \"../../../hooks/use-floating-element.js\";\nimport { Button } from \"../../ui/button.js\";\nimport { Input } from \"../../ui/input.js\";\nimport { Switch } from \"../../ui/switch.js\";\nimport type { ChipKind } from \"../tag-chip-decoration.js\";\n\nconst SIMPLE_FIELD_RE = /^\\{\\{\\s*([a-zA-Z_][a-zA-Z0-9_.]*)\\s*(\\|\\s*default:\\s*\"\")?\\s*\\}\\}$/;\nconst SECRET_RE = /^\\{\\{\\s*SECRETS\\.([A-Z][A-Z0-9_]*)\\s*\\}\\}$/;\nconst CONSTANT_RE = /^\\{\\{\\s*CONSTANTS\\.([A-Z][A-Z0-9_]*)\\s*\\}\\}$/;\n// `{% output NAME, key: \"value\", key: true, ... %}` in any argument order. The\n// args are split out by OUTPUT_ARG_RE; BlockChipBody only edits the keys it\n// knows and falls back to the raw \"advanced\" view for anything else.\nconst OUTPUT_BLOCK_RE =\n /^\\{%\\s*output\\s+([A-Za-z_][A-Za-z0-9_]*)\\s*((?:,\\s*[a-z_]+:\\s*(?:\"(?:[^\"\\\\]|\\\\.)*\"|true|false)\\s*)*)%\\}$/;\nconst OUTPUT_ARG_RE = /([a-z_]+):\\s*(\"(?:[^\"\\\\]|\\\\.)*\"|true|false)/g;\nconst OUTPUT_KEYS = new Set([\"type\", \"schema\", \"description\", \"format\", \"required\"]);\n\ntype OutputType = \"string\" | \"number\" | \"boolean\" | \"json\" | \"unknown\";\n\nfunction parseOutputBlock(raw: string) {\n const m = raw.match(OUTPUT_BLOCK_RE);\n if (!m) return null;\n const args: Record<string, string | boolean> = {};\n for (const [, key, value] of (m[2] ?? \"\").matchAll(OUTPUT_ARG_RE)) {\n if (!key || !value || !OUTPUT_KEYS.has(key)) return null;\n args[key] =\n value === \"true\" || value === \"false\"\n ? value === \"true\"\n : value.slice(1, -1).replace(/\\\\\"/g, '\"').replace(/\\\\\\\\/g, \"\\\\\");\n }\n const type = args.type;\n if (typeof type !== \"string\" || !(type in TYPES_TO_FORMATS)) return null;\n // A hand-written format the type does not take has no option to show; keep\n // the raw view rather than silently dropping it on save.\n const format = args.format;\n if (\n typeof format === \"string\" &&\n type !== \"json\" &&\n !(TYPES_TO_FORMATS[type as OutputType] as readonly string[]).includes(format)\n ) {\n return null;\n }\n return {\n name: m[1] ?? \"\",\n type: type as OutputType,\n schema: typeof args.schema === \"string\" ? args.schema : \"\",\n description: typeof args.description === \"string\" ? args.description : \"\",\n format: typeof args.format === \"string\" ? args.format : \"\",\n required: typeof args.required === \"boolean\" ? args.required : undefined,\n };\n}\n\nexport interface ChipEditTarget {\n kind: ChipKind;\n raw: string;\n from: number;\n to: number;\n rect: DOMRect;\n}\n\n/**\n * Contextual popover anchored to a chip's DOM rect. Different content per\n * chip kind:\n * - field: switch for `| default: \"\"` (simple cases only), remove.\n * - secret: publicId header, manage/remove buttons. Power users still\n * edit by hand.\n * - block (output declaration): name / type / format / description editors.\n *\n * On any mutation, the popover dispatches a single replaceWith transaction\n * over the chip's range, then closes itself. The Liquid serialization\n * stays identical to what would have been authored by hand.\n */\nexport function ChipEditPopover({\n editor,\n target,\n onClose,\n}: {\n editor: Editor;\n target: ChipEditTarget;\n onClose: () => void;\n}) {\n const { ref, style, isMounted, getFloatingProps } = useFloatingElement(true, target.rect, 1100, {\n placement: \"bottom-start\",\n middleware: [offset(6), shift()],\n onOpenChange(open) {\n if (!open) onClose();\n },\n dismissOptions: { outsidePress: true, outsidePressEvent: \"mousedown\" },\n });\n\n const popupRef = useRef<HTMLDivElement | null>(null);\n\n useEffect(() => {\n function onKey(e: KeyboardEvent) {\n if (e.key === \"Escape\") onClose();\n }\n window.addEventListener(\"keydown\", onKey);\n return () => window.removeEventListener(\"keydown\", onKey);\n }, [onClose]);\n\n function replaceWith(next: string) {\n editor.chain().focus().insertContentAt({ from: target.from, to: target.to }, next).run();\n onClose();\n }\n\n function remove() {\n editor.chain().focus().deleteRange({ from: target.from, to: target.to }).run();\n onClose();\n }\n\n if (!isMounted) return null;\n\n return (\n <div\n ref={(el) => {\n popupRef.current = el;\n ref(el);\n }}\n style={style}\n {...getFloatingProps()}\n onMouseDown={(e) => e.stopPropagation()}\n className=\"pz:flex pz:flex-col pz:gap-2 pz:rounded-md pz:border pz:border-input pz:bg-popover pz:p-3 pz:text-popover-foreground pz:shadow-md pz:min-w-72\"\n role=\"dialog\"\n aria-label={`Edit ${target.kind} chip`}\n >\n {target.kind === \"field\" && (\n <FieldChipBody raw={target.raw} replaceWith={replaceWith} remove={remove} />\n )}\n {target.kind === \"secret\" && <SecretChipBody raw={target.raw} remove={remove} />}\n {target.kind === \"constant\" && <ConstantChipBody raw={target.raw} remove={remove} />}\n {target.kind === \"block\" && (\n <BlockChipBody raw={target.raw} replaceWith={replaceWith} remove={remove} />\n )}\n </div>\n );\n}\n\nfunction FieldChipBody({\n raw,\n replaceWith,\n remove,\n}: {\n raw: string;\n replaceWith: (next: string) => void;\n remove: () => void;\n}) {\n const match = raw.match(SIMPLE_FIELD_RE);\n const name = match?.[1];\n const allowEmpty = !!match?.[2];\n const isSimple = !!match;\n\n if (!isSimple || !name) {\n return (\n <>\n <header className=\"pz:text-xs pz:font-medium pz:text-muted-foreground\">\n Field reference (advanced)\n </header>\n <p className=\"pz:text-xs pz:text-muted-foreground\">\n This chip uses a custom Liquid filter chain. Edit the raw text in the editor to change it.\n </p>\n <pre className=\"pz:overflow-x-auto pz:rounded-sm pz:bg-muted pz:px-2 pz:py-1 pz:text-xs\">\n {raw}\n </pre>\n <Button type=\"button\" variant=\"outline\" size=\"sm\" onClick={remove}>\n <Trash2 className=\"pz:size-3.5 pz:mr-1\" />\n Remove\n </Button>\n </>\n );\n }\n\n function toggleAllowEmpty() {\n replaceWith(allowEmpty ? `{{ ${name} }}` : `{{ ${name} | default: \"\" }}`);\n }\n\n return (\n <>\n <header className=\"pz:flex pz:items-center pz:justify-between pz:gap-2\">\n <span className=\"pz:text-xs pz:font-medium pz:text-muted-foreground\">Field reference</span>\n <code className=\"pz:text-xs pz:text-sky-700\">{name}</code>\n </header>\n <div className=\"pz:flex pz:items-center pz:justify-between pz:gap-3 pz:text-sm\">\n <span className=\"pz:flex pz:flex-col\">\n <span>Allow empty</span>\n <span className=\"pz:text-xs pz:text-muted-foreground\">\n Inserts <code>| default: \"\"</code> so missing values render as empty.\n </span>\n </span>\n <Switch checked={allowEmpty} onCheckedChange={toggleAllowEmpty} />\n </div>\n <Button type=\"button\" variant=\"outline\" size=\"sm\" onClick={remove}>\n <Trash2 className=\"pz:size-3.5 pz:mr-1\" />\n Remove\n </Button>\n </>\n );\n}\n\nfunction SecretChipBody({ raw, remove }: { raw: string; remove: () => void }) {\n const publicId = raw.match(SECRET_RE)?.[1];\n\n return (\n <>\n <header className=\"pz:flex pz:items-center pz:justify-between pz:gap-2\">\n <span className=\"pz:text-xs pz:font-medium pz:text-muted-foreground\">Secret reference</span>\n <code className=\"pz:text-xs pz:text-amber-700\">{publicId ?? \"(unknown)\"}</code>\n </header>\n <Button type=\"button\" variant=\"outline\" size=\"sm\" onClick={remove}>\n <Trash2 className=\"pz:size-3.5 pz:mr-1\" />\n Remove\n </Button>\n </>\n );\n}\n\nfunction ConstantChipBody({ raw, remove }: { raw: string; remove: () => void }) {\n const publicId = raw.match(CONSTANT_RE)?.[1];\n\n return (\n <>\n <header className=\"pz:flex pz:items-center pz:justify-between pz:gap-2\">\n <span className=\"pz:text-xs pz:font-medium pz:text-muted-foreground\">\n Constant reference\n </span>\n <code className=\"pz:text-xs pz:text-emerald-700\">{publicId ?? \"(unknown)\"}</code>\n </header>\n <Button type=\"button\" variant=\"outline\" size=\"sm\" onClick={remove}>\n <Trash2 className=\"pz:size-3.5 pz:mr-1\" />\n Remove\n </Button>\n </>\n );\n}\n\nfunction BlockChipBody({\n raw,\n replaceWith,\n remove,\n}: {\n raw: string;\n replaceWith: (next: string) => void;\n remove: () => void;\n}) {\n const initial = useMemo(() => parseOutputBlock(raw), [raw]);\n\n const [name, setName] = useState(initial?.name ?? \"\");\n const [type, setType] = useState<OutputType>(initial?.type ?? \"string\");\n const [schema, setSchema] = useState(initial?.schema ?? \"\");\n const [description, setDescription] = useState(initial?.description ?? \"\");\n const [format, setFormat] = useState(initial?.format ?? \"\");\n const formatOptions: readonly string[] = TYPES_TO_FORMATS[type];\n const idPrefix = useId();\n const nameId = `${idPrefix}-name`;\n const typeId = `${idPrefix}-type`;\n const schemaId = `${idPrefix}-schema`;\n const descId = `${idPrefix}-desc`;\n const formatId = `${idPrefix}-format`;\n\n if (!initial) {\n return (\n <>\n <header className=\"pz:text-xs pz:font-medium pz:text-muted-foreground\">\n Block (advanced)\n </header>\n <p className=\"pz:text-xs pz:text-muted-foreground\">\n This block uses a non-standard form. Edit the raw text in the editor.\n </p>\n <pre className=\"pz:overflow-x-auto pz:rounded-sm pz:bg-muted pz:px-2 pz:py-1 pz:text-xs\">\n {raw}\n </pre>\n <Button type=\"button\" variant=\"outline\" size=\"sm\" onClick={remove}>\n <Trash2 className=\"pz:size-3.5 pz:mr-1\" />\n Remove\n </Button>\n </>\n );\n }\n\n function save() {\n if (!name.trim()) return;\n const escaped = description.replace(/\\\\/g, \"\\\\\\\\\").replace(/\"/g, '\\\\\"');\n const parts = [`{% output ${name.trim()}`, `type: \"${type}\"`];\n if (type === \"json\" && schema.trim()) parts.push(`schema: \"${schema.trim()}\"`);\n if (format && formatOptions.includes(format)) parts.push(`format: \"${format}\"`);\n parts.push(`description: \"${escaped}\"`);\n if (initial?.required !== undefined) parts.push(`required: ${initial.required}`);\n replaceWith(`${parts.join(\", \")} %}`);\n }\n\n return (\n <>\n <header className=\"pz:text-xs pz:font-medium pz:text-muted-foreground\">\n Output declaration\n </header>\n <label htmlFor={nameId} className=\"pz:flex pz:flex-col pz:gap-1 pz:text-xs\">\n <span>Name</span>\n <Input\n id={nameId}\n value={name}\n onChange={(e) => setName(e.target.value)}\n placeholder=\"FIELD_NAME\"\n />\n </label>\n <label htmlFor={typeId} className=\"pz:flex pz:flex-col pz:gap-1 pz:text-xs\">\n <span>Type</span>\n <select\n id={typeId}\n value={type}\n onChange={(e) => {\n const next = e.target.value as OutputType;\n setType(next);\n // A format that the new type does not take would fail validation.\n if (!(TYPES_TO_FORMATS[next] as readonly string[]).includes(format)) setFormat(\"\");\n }}\n className=\"pz:rounded-sm pz:border pz:border-input pz:bg-transparent pz:px-2 pz:py-1 pz:text-sm\"\n >\n <option value=\"string\">string</option>\n <option value=\"number\">number</option>\n <option value=\"boolean\">boolean</option>\n <option value=\"json\">json</option>\n <option value=\"unknown\">unknown</option>\n </select>\n </label>\n {type === \"json\" && (\n <label htmlFor={schemaId} className=\"pz:flex pz:flex-col pz:gap-1 pz:text-xs\">\n <span>Schema</span>\n <Input\n id={schemaId}\n value={schema}\n onChange={(e) => setSchema(e.target.value)}\n placeholder=\"SCHEMA_NAME\"\n />\n </label>\n )}\n {type !== \"json\" && formatOptions.length > 0 && (\n <label htmlFor={formatId} className=\"pz:flex pz:flex-col pz:gap-1 pz:text-xs\">\n <span>Format</span>\n <select\n id={formatId}\n value={format}\n onChange={(e) => setFormat(e.target.value)}\n className=\"pz:rounded-sm pz:border pz:border-input pz:bg-transparent pz:px-2 pz:py-1 pz:text-sm\"\n >\n <option value=\"\">none</option>\n {formatOptions.map((f) => (\n <option key={f} value={f}>\n {f}\n </option>\n ))}\n </select>\n </label>\n )}\n <label htmlFor={descId} className=\"pz:flex pz:flex-col pz:gap-1 pz:text-xs\">\n <span>Description</span>\n <Input id={descId} value={description} onChange={(e) => setDescription(e.target.value)} />\n </label>\n <div className=\"pz:flex pz:items-center pz:justify-between pz:gap-2 pz:pt-1\">\n <Button type=\"button\" variant=\"ghost\" size=\"sm\" onClick={remove}>\n <Trash2 className=\"pz:size-3.5 pz:mr-1\" />\n Remove\n </Button>\n <Button type=\"button\" size=\"sm\" onClick={save}>\n Save\n </Button>\n </div>\n </>\n );\n}\n"],"mappings":"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"}