@pipe0/react 0.2.5 → 0.2.6

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 (37) hide show
  1. package/CHANGELOG.md +8 -0
  2. package/dist/components/defaults/adapters/context-select-input.mjs +20 -1
  3. package/dist/components/defaults/adapters/context-select-input.mjs.map +1 -1
  4. package/dist/components/defaults/adapters/field-select-input.mjs +33 -0
  5. package/dist/components/defaults/adapters/field-select-input.mjs.map +1 -0
  6. package/dist/components/defaults/adapters/index.d.mts.map +1 -1
  7. package/dist/components/defaults/adapters/index.mjs +4 -0
  8. package/dist/components/defaults/adapters/index.mjs.map +1 -1
  9. package/dist/components/defaults/adapters/pipes-run-if-input.mjs +53 -5
  10. package/dist/components/defaults/adapters/pipes-run-if-input.mjs.map +1 -1
  11. package/dist/components/defaults/adapters/typed-fields-select-input.mjs +48 -0
  12. package/dist/components/defaults/adapters/typed-fields-select-input.mjs.map +1 -0
  13. package/dist/components/internal/combobox/suggest-combobox.mjs +35 -6
  14. package/dist/components/internal/combobox/suggest-combobox.mjs.map +1 -1
  15. package/dist/hooks/use-effect-catalog-table.d.mts.map +1 -1
  16. package/dist/hooks/use-effect-catalog-table.mjs +18 -11
  17. package/dist/hooks/use-effect-catalog-table.mjs.map +1 -1
  18. package/dist/hooks/use-form-core.d.mts.map +1 -1
  19. package/dist/hooks/use-form-core.mjs +26 -8
  20. package/dist/hooks/use-form-core.mjs.map +1 -1
  21. package/dist/hooks/use-pipe-catalog-table.d.mts +8 -8
  22. package/dist/hooks/use-pipe-catalog-table.d.mts.map +1 -1
  23. package/dist/hooks/use-pipe-catalog-table.mjs +20 -16
  24. package/dist/hooks/use-pipe-catalog-table.mjs.map +1 -1
  25. package/dist/hooks/use-search-catalog-table.d.mts.map +1 -1
  26. package/dist/hooks/use-search-catalog-table.mjs +20 -13
  27. package/dist/hooks/use-search-catalog-table.mjs.map +1 -1
  28. package/dist/hooks/use-searches-catalog-table.d.mts.map +1 -1
  29. package/dist/hooks/use-searches-catalog-table.mjs +20 -13
  30. package/dist/hooks/use-searches-catalog-table.mjs.map +1 -1
  31. package/dist/types/field-props.d.mts +35 -2
  32. package/dist/types/field-props.d.mts.map +1 -1
  33. package/dist/utils/build-section-handlers.mjs +21 -2
  34. package/dist/utils/build-section-handlers.mjs.map +1 -1
  35. package/dist/utils/catalog-helpers.mjs +10 -1
  36. package/dist/utils/catalog-helpers.mjs.map +1 -1
  37. package/package.json +2 -2
package/CHANGELOG.md CHANGED
@@ -1,5 +1,13 @@
1
1
  # @pipe0/elements-react
2
2
 
3
+ ## 0.2.6
4
+
5
+ ### Patch Changes
6
+
7
+ - cbc1fc4: round robin and search improvements
8
+ - Updated dependencies [cbc1fc4]
9
+ - @pipe0/base@0.5.6
10
+
3
11
  ## 0.2.5
4
12
 
5
13
  ### Patch Changes
@@ -132,13 +132,17 @@ function ContextSelectInputAdapter(field) {
132
132
  const hasOptions = field.options.length > 0;
133
133
  const selectedOption = field.options.find((o) => o.value === field.selectedValue);
134
134
  if (field.meta.mappingPath) return /* @__PURE__ */ jsx(MappedContextSelect, { ...field });
135
+ const labelFor = (value) => field.options.find((o) => o.value === value)?.label ?? value;
135
136
  if (field.meta.allowCreate) return /* @__PURE__ */ jsxs("div", {
136
137
  "data-p0": "input",
137
138
  className: cn("pz:flex pz:flex-col pz:gap-1", field.pending && "pz:opacity-60"),
138
139
  children: [/* @__PURE__ */ jsx(SuggestCombobox, {
140
+ single: true,
139
141
  value: field.selectedValue ? [field.selectedValue] : [],
140
142
  onChange: (next) => field.onSelect(next.at(-1) ?? ""),
141
- options: field.options,
143
+ options: field.loadOptions ? void 0 : field.options,
144
+ loadOptions: field.loadOptions,
145
+ labelFor,
142
146
  allowCreate: true,
143
147
  disabled: field.pending,
144
148
  ariaInvalid: !!field.error,
@@ -149,6 +153,21 @@ function ContextSelectInputAdapter(field) {
149
153
  children: [field.suggestionsDisabledReason ?? "Suggestions unavailable", " "]
150
154
  })]
151
155
  });
156
+ if (field.loadOptions && !field.suggestionsDisabled) return /* @__PURE__ */ jsx("div", {
157
+ "data-p0": "input",
158
+ className: cn("pz:flex pz:flex-col pz:gap-1", field.pending && "pz:opacity-60"),
159
+ children: /* @__PURE__ */ jsx(SuggestCombobox, {
160
+ single: true,
161
+ value: field.selectedValue ? [field.selectedValue] : [],
162
+ onChange: (next) => field.onSelect(next.at(-1) ?? ""),
163
+ loadOptions: field.loadOptions,
164
+ labelFor,
165
+ disabled: field.pending,
166
+ ariaInvalid: !!field.error,
167
+ placeholder: field.pending ? "Loading…" : field.meta.placeholder ?? "Search…",
168
+ emptyLabel: "No matches"
169
+ })
170
+ });
152
171
  const placeholder = field.pending ? "Loading…" : field.meta.placeholder ?? "";
153
172
  return /* @__PURE__ */ jsxs("div", {
154
173
  "data-p0": "input",
@@ -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\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 // 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 value={field.selectedValue ? [field.selectedValue] : []}\n onChange={(next) => field.onSelect(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:gap-y-1 pz:text-muted-foreground pz:italic\">\n {field.suggestionsDisabledReason ?? \"Suggestions unavailable\"}{\" \"}\n </div>\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\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 // 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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"}
@@ -0,0 +1,33 @@
1
+ import { SuggestCombobox } from "../../internal/combobox/suggest-combobox.mjs";
2
+ import { jsx } from "react/jsx-runtime";
3
+
4
+ //#region src/components/defaults/adapters/field-select-input.tsx
5
+ /**
6
+ * Single-column picker storing `{ field_name }`. Options are either the
7
+ * current sheet's columns (build-time) or, when the meta carries an
8
+ * `optionsDef`, fetched via field context (e.g. the columns of a
9
+ * sibling-selected sheet). `allowCreate` keeps free typing possible — a
10
+ * column that isn't (yet) suggested is still a valid literal name.
11
+ */
12
+ function FieldSelectInputAdapter(field) {
13
+ const current = field.value?.field_name ?? "";
14
+ return /* @__PURE__ */ jsx("div", {
15
+ "data-p0": "input",
16
+ children: /* @__PURE__ */ jsx(SuggestCombobox, {
17
+ single: true,
18
+ value: current ? [current] : [],
19
+ onChange: (next) => field.setValue({ field_name: next[next.length - 1] ?? "" }),
20
+ options: field.options ?? [],
21
+ allowCreate: true,
22
+ disableSearch: field.meta.disableSearch,
23
+ disabled: field.disabled,
24
+ ariaInvalid: !!field.error,
25
+ placeholder: field.meta.placeholder ?? "Select field…",
26
+ emptyLabel: field.pending ? "Loading fields…" : "No fields available"
27
+ })
28
+ });
29
+ }
30
+
31
+ //#endregion
32
+ export { FieldSelectInputAdapter };
33
+ //# sourceMappingURL=field-select-input.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"field-select-input.mjs","names":[],"sources":["../../../../src/components/defaults/adapters/field-select-input.tsx"],"sourcesContent":["import type { FieldHandle } from \"../../../types/field-handle.js\";\nimport { SuggestCombobox } from \"../../internal/combobox/suggest-combobox.js\";\n\n/**\n * Single-column picker storing `{ field_name }`. Options are either the\n * current sheet's columns (build-time) or, when the meta carries an\n * `optionsDef`, fetched via field context (e.g. the columns of a\n * sibling-selected sheet). `allowCreate` keeps free typing possible — a\n * column that isn't (yet) suggested is still a valid literal name.\n */\nexport function FieldSelectInputAdapter(field: FieldHandle<\"field_select_input\">) {\n const current = field.value?.field_name ?? \"\";\n\n return (\n <div data-p0=\"input\">\n <SuggestCombobox\n single\n value={current ? [current] : []}\n onChange={(next) => field.setValue({ field_name: next[next.length - 1] ?? \"\" })}\n options={field.options ?? []}\n allowCreate\n disableSearch={field.meta.disableSearch}\n disabled={field.disabled}\n ariaInvalid={!!field.error}\n placeholder={field.meta.placeholder ?? \"Select field…\"}\n emptyLabel={field.pending ? \"Loading fields…\" : \"No fields available\"}\n />\n </div>\n );\n}\n"],"mappings":";;;;;;;;;;;AAUA,SAAgB,wBAAwB,OAA0C;CAChF,MAAM,UAAU,MAAM,OAAO,cAAc;AAE3C,QACE,oBAAC,OAAD;EAAK,WAAQ;YACX,oBAAC,iBAAD;GACE;GACA,OAAO,UAAU,CAAC,QAAQ,GAAG,EAAE;GAC/B,WAAW,SAAS,MAAM,SAAS,EAAE,YAAY,KAAK,KAAK,SAAS,MAAM,IAAI,CAAC;GAC/E,SAAS,MAAM,WAAW,EAAE;GAC5B;GACA,eAAe,MAAM,KAAK;GAC1B,UAAU,MAAM;GAChB,aAAa,CAAC,CAAC,MAAM;GACrB,aAAa,MAAM,KAAK,eAAe;GACvC,YAAY,MAAM,UAAU,oBAAoB;GAChD;EACE"}
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.mts","names":[],"sources":["../../../../src/components/defaults/adapters/index.ts"],"mappings":";;;;;AAsCA;;cAAa,eAAA,EAoC2B,OAAA,CAAQ,eAAA"}
1
+ {"version":3,"file":"index.d.mts","names":[],"sources":["../../../../src/components/defaults/adapters/index.ts"],"mappings":";;;;;AAwCA;;cAAa,eAAA,EAsC2B,OAAA,CAAQ,eAAA"}
@@ -6,6 +6,7 @@ import { ContextSelectInputAdapter } from "./context-select-input.mjs";
6
6
  import { CursorPaginationInputAdapter } from "./cursor-pagination-input.mjs";
7
7
  import { DateRangeInputAdapter } from "./date-range-input.mjs";
8
8
  import { ExactRangeInputAdapter } from "./exact-range-input.mjs";
9
+ import { FieldSelectInputAdapter } from "./field-select-input.mjs";
9
10
  import { FieldsSelectInputAdapter } from "./fields-select-input.mjs";
10
11
  import { IncludeExcludeInputAdapter } from "./include-exclude-input.mjs";
11
12
  import { IncludeExcludeSelectInputAdapter } from "./include-exclude-select-input.mjs";
@@ -30,6 +31,7 @@ import { TaggedTextInputAdapter } from "./tagged-text-input.mjs";
30
31
  import { TemplateInputAdapter } from "./template-input.mjs";
31
32
  import { TextInputAdapter } from "./text-input.mjs";
32
33
  import { TextareaInputAdapter } from "./textarea-input.mjs";
34
+ import { TypedFieldsSelectInputAdapter } from "./typed-fields-select-input.mjs";
33
35
 
34
36
  //#region src/components/defaults/adapters/index.ts
35
37
  /**
@@ -68,6 +70,8 @@ const defaultAdapters = {
68
70
  connector_input: ConnectorInputAdapter,
69
71
  providers_input: ProvidersInputAdapter,
70
72
  fields_select_input: FieldsSelectInputAdapter,
73
+ typed_fields_select_input: TypedFieldsSelectInputAdapter,
74
+ field_select_input: FieldSelectInputAdapter,
71
75
  output_field_input: OutputFieldInputAdapter,
72
76
  cursor_pagination_metadata: CursorPaginationInputAdapter,
73
77
  search_payload_input: SearchPayloadInputAdapter
@@ -1 +1 @@
1
- {"version":3,"file":"index.mjs","names":[],"sources":["../../../../src/components/defaults/adapters/index.ts"],"sourcesContent":["import type { FieldAdapterMap } from \"../../../types/adapters.js\";\nimport { AsyncIncludeExcludeSelectInputAdapter } from \"./async-include-exclude-select-input.js\";\nimport { AsyncMultiSelectInputAdapter } from \"./async-multi-select-input.js\";\nimport { BooleanInputAdapter } from \"./boolean-input.js\";\nimport { ConnectorInputAdapter } from \"./connector-input.js\";\nimport { ContextSelectInputAdapter } from \"./context-select-input.js\";\nimport { CursorPaginationInputAdapter } from \"./cursor-pagination-input.js\";\nimport { DateRangeInputAdapter } from \"./date-range-input.js\";\nimport { ExactRangeInputAdapter } from \"./exact-range-input.js\";\nimport { FieldsSelectInputAdapter } from \"./fields-select-input.js\";\nimport { IncludeExcludeInputAdapter } from \"./include-exclude-input.js\";\nimport { IncludeExcludeSelectInputAdapter } from \"./include-exclude-select-input.js\";\nimport { IntInputAdapter } from \"./int-input.js\";\nimport { JsonExtractionInputAdapter } from \"./json-extraction-input.js\";\nimport { JsonSchemaInputAdapter } from \"./json-schema-input.js\";\nimport { LooseObjectInputAdapter } from \"./loose-object-input.js\";\nimport { MinMaxIntInputAdapter } from \"./min-max-int-input.js\";\nimport { MultiCreateInputAdapter } from \"./multi-create-input.js\";\nimport { MultiSelectInputAdapter } from \"./multi-select-input.js\";\nimport { NumberInputAdapter } from \"./number-input.js\";\nimport { OrderedMultiCreateInputAdapter } from \"./ordered-multi-create-input.js\";\nimport { OutputFieldInputAdapter } from \"./output-field-input.js\";\nimport { ConditionBlockInputAdapter, PipesRunIfInputAdapter } from \"./pipes-run-if-input.js\";\nimport { PromptInputAdapter } from \"./prompt-input.js\";\nimport { ProvidersInputAdapter } from \"./providers-input.js\";\nimport { RangeInputAdapter } from \"./range-input.js\";\nimport { SearchPayloadInputAdapter } from \"./search-payload-input.js\";\nimport { SelectInputAdapter } from \"./select-input.js\";\nimport { TaggedOrderedMultiCreateInputAdapter } from \"./tagged-ordered-multi-create-input.js\";\nimport { TaggedTextInputAdapter } from \"./tagged-text-input.js\";\nimport { TemplateInputAdapter } from \"./template-input.js\";\nimport { TextInputAdapter } from \"./text-input.js\";\nimport { TextareaInputAdapter } from \"./textarea-input.js\";\n\n/**\n * Default field adapters for all known field kinds.\n * Users can override any of these via `<FormProvider adapters={...}>`.\n */\nexport const defaultAdapters = {\n text_input: TextInputAdapter,\n textarea_input: TextareaInputAdapter,\n int_input: IntInputAdapter,\n number_input: NumberInputAdapter,\n select_input: SelectInputAdapter,\n boolean_input: BooleanInputAdapter,\n nullable_boolean_input: BooleanInputAdapter,\n range_input: RangeInputAdapter,\n date_range_input: DateRangeInputAdapter,\n multi_select_input: MultiSelectInputAdapter,\n include_exclude_input: IncludeExcludeInputAdapter,\n multi_create_input: MultiCreateInputAdapter,\n context_select_input: ContextSelectInputAdapter,\n async_multi_select_input: AsyncMultiSelectInputAdapter,\n async_include_exclude_select_input: AsyncIncludeExcludeSelectInputAdapter,\n include_exclude_select_input: IncludeExcludeSelectInputAdapter,\n exact_range_input: ExactRangeInputAdapter,\n min_max_int_input: MinMaxIntInputAdapter,\n ordered_multi_create_input: OrderedMultiCreateInputAdapter,\n tagged_ordered_multi_create_input: TaggedOrderedMultiCreateInputAdapter,\n prompt_input: PromptInputAdapter,\n template_input: TemplateInputAdapter,\n tagged_text_input: TaggedTextInputAdapter,\n loose_object_input: LooseObjectInputAdapter,\n json_schema_input: JsonSchemaInputAdapter,\n json_extraction_input: JsonExtractionInputAdapter,\n pipes_run_if_input: PipesRunIfInputAdapter,\n condition_block_input: ConditionBlockInputAdapter,\n connector_input: ConnectorInputAdapter,\n providers_input: ProvidersInputAdapter,\n fields_select_input: FieldsSelectInputAdapter,\n output_field_input: OutputFieldInputAdapter,\n cursor_pagination_metadata: CursorPaginationInputAdapter,\n // Renders nothing by default — consumers (e.g. apps/dash) override this.\n search_payload_input: SearchPayloadInputAdapter,\n} satisfies Partial<FieldAdapterMap> as Partial<FieldAdapterMap>;\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAsCA,MAAa,kBAAkB;CAC7B,YAAY;CACZ,gBAAgB;CAChB,WAAW;CACX,cAAc;CACd,cAAc;CACd,eAAe;CACf,wBAAwB;CACxB,aAAa;CACb,kBAAkB;CAClB,oBAAoB;CACpB,uBAAuB;CACvB,oBAAoB;CACpB,sBAAsB;CACtB,0BAA0B;CAC1B,oCAAoC;CACpC,8BAA8B;CAC9B,mBAAmB;CACnB,mBAAmB;CACnB,4BAA4B;CAC5B,mCAAmC;CACnC,cAAc;CACd,gBAAgB;CAChB,mBAAmB;CACnB,oBAAoB;CACpB,mBAAmB;CACnB,uBAAuB;CACvB,oBAAoB;CACpB,uBAAuB;CACvB,iBAAiB;CACjB,iBAAiB;CACjB,qBAAqB;CACrB,oBAAoB;CACpB,4BAA4B;CAE5B,sBAAsB;CACvB"}
1
+ {"version":3,"file":"index.mjs","names":[],"sources":["../../../../src/components/defaults/adapters/index.ts"],"sourcesContent":["import type { FieldAdapterMap } from \"../../../types/adapters.js\";\nimport { AsyncIncludeExcludeSelectInputAdapter } from \"./async-include-exclude-select-input.js\";\nimport { AsyncMultiSelectInputAdapter } from \"./async-multi-select-input.js\";\nimport { BooleanInputAdapter } from \"./boolean-input.js\";\nimport { ConnectorInputAdapter } from \"./connector-input.js\";\nimport { ContextSelectInputAdapter } from \"./context-select-input.js\";\nimport { CursorPaginationInputAdapter } from \"./cursor-pagination-input.js\";\nimport { DateRangeInputAdapter } from \"./date-range-input.js\";\nimport { ExactRangeInputAdapter } from \"./exact-range-input.js\";\nimport { FieldSelectInputAdapter } from \"./field-select-input.js\";\nimport { FieldsSelectInputAdapter } from \"./fields-select-input.js\";\nimport { IncludeExcludeInputAdapter } from \"./include-exclude-input.js\";\nimport { IncludeExcludeSelectInputAdapter } from \"./include-exclude-select-input.js\";\nimport { IntInputAdapter } from \"./int-input.js\";\nimport { JsonExtractionInputAdapter } from \"./json-extraction-input.js\";\nimport { JsonSchemaInputAdapter } from \"./json-schema-input.js\";\nimport { LooseObjectInputAdapter } from \"./loose-object-input.js\";\nimport { MinMaxIntInputAdapter } from \"./min-max-int-input.js\";\nimport { MultiCreateInputAdapter } from \"./multi-create-input.js\";\nimport { MultiSelectInputAdapter } from \"./multi-select-input.js\";\nimport { NumberInputAdapter } from \"./number-input.js\";\nimport { OrderedMultiCreateInputAdapter } from \"./ordered-multi-create-input.js\";\nimport { OutputFieldInputAdapter } from \"./output-field-input.js\";\nimport { ConditionBlockInputAdapter, PipesRunIfInputAdapter } from \"./pipes-run-if-input.js\";\nimport { PromptInputAdapter } from \"./prompt-input.js\";\nimport { ProvidersInputAdapter } from \"./providers-input.js\";\nimport { RangeInputAdapter } from \"./range-input.js\";\nimport { SearchPayloadInputAdapter } from \"./search-payload-input.js\";\nimport { SelectInputAdapter } from \"./select-input.js\";\nimport { TaggedOrderedMultiCreateInputAdapter } from \"./tagged-ordered-multi-create-input.js\";\nimport { TaggedTextInputAdapter } from \"./tagged-text-input.js\";\nimport { TemplateInputAdapter } from \"./template-input.js\";\nimport { TextInputAdapter } from \"./text-input.js\";\nimport { TextareaInputAdapter } from \"./textarea-input.js\";\nimport { TypedFieldsSelectInputAdapter } from \"./typed-fields-select-input.js\";\n\n/**\n * Default field adapters for all known field kinds.\n * Users can override any of these via `<FormProvider adapters={...}>`.\n */\nexport const defaultAdapters = {\n text_input: TextInputAdapter,\n textarea_input: TextareaInputAdapter,\n int_input: IntInputAdapter,\n number_input: NumberInputAdapter,\n select_input: SelectInputAdapter,\n boolean_input: BooleanInputAdapter,\n nullable_boolean_input: BooleanInputAdapter,\n range_input: RangeInputAdapter,\n date_range_input: DateRangeInputAdapter,\n multi_select_input: MultiSelectInputAdapter,\n include_exclude_input: IncludeExcludeInputAdapter,\n multi_create_input: MultiCreateInputAdapter,\n context_select_input: ContextSelectInputAdapter,\n async_multi_select_input: AsyncMultiSelectInputAdapter,\n async_include_exclude_select_input: AsyncIncludeExcludeSelectInputAdapter,\n include_exclude_select_input: IncludeExcludeSelectInputAdapter,\n exact_range_input: ExactRangeInputAdapter,\n min_max_int_input: MinMaxIntInputAdapter,\n ordered_multi_create_input: OrderedMultiCreateInputAdapter,\n tagged_ordered_multi_create_input: TaggedOrderedMultiCreateInputAdapter,\n prompt_input: PromptInputAdapter,\n template_input: TemplateInputAdapter,\n tagged_text_input: TaggedTextInputAdapter,\n loose_object_input: LooseObjectInputAdapter,\n json_schema_input: JsonSchemaInputAdapter,\n json_extraction_input: JsonExtractionInputAdapter,\n pipes_run_if_input: PipesRunIfInputAdapter,\n condition_block_input: ConditionBlockInputAdapter,\n connector_input: ConnectorInputAdapter,\n providers_input: ProvidersInputAdapter,\n fields_select_input: FieldsSelectInputAdapter,\n typed_fields_select_input: TypedFieldsSelectInputAdapter,\n field_select_input: FieldSelectInputAdapter,\n output_field_input: OutputFieldInputAdapter,\n cursor_pagination_metadata: CursorPaginationInputAdapter,\n // Renders nothing by default — consumers (e.g. apps/dash) override this.\n search_payload_input: SearchPayloadInputAdapter,\n} satisfies Partial<FieldAdapterMap> as Partial<FieldAdapterMap>;\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAwCA,MAAa,kBAAkB;CAC7B,YAAY;CACZ,gBAAgB;CAChB,WAAW;CACX,cAAc;CACd,cAAc;CACd,eAAe;CACf,wBAAwB;CACxB,aAAa;CACb,kBAAkB;CAClB,oBAAoB;CACpB,uBAAuB;CACvB,oBAAoB;CACpB,sBAAsB;CACtB,0BAA0B;CAC1B,oCAAoC;CACpC,8BAA8B;CAC9B,mBAAmB;CACnB,mBAAmB;CACnB,4BAA4B;CAC5B,mCAAmC;CACnC,cAAc;CACd,gBAAgB;CAChB,mBAAmB;CACnB,oBAAoB;CACpB,mBAAmB;CACnB,uBAAuB;CACvB,oBAAoB;CACpB,uBAAuB;CACvB,iBAAiB;CACjB,iBAAiB;CACjB,qBAAqB;CACrB,2BAA2B;CAC3B,oBAAoB;CACpB,oBAAoB;CACpB,4BAA4B;CAE5B,sBAAsB;CACvB"}
@@ -6,6 +6,7 @@ import { IconPlus } from "../../internal/icons.mjs";
6
6
  import { HoverInfo } from "../../hover-info.mjs";
7
7
  import { Badge } from "../../ui/badge.mjs";
8
8
  import { useFieldError } from "../../../hooks/use-field-error.mjs";
9
+ import { SuggestCombobox } from "../../internal/combobox/suggest-combobox.mjs";
9
10
  import { FieldLegend } from "../../internal/field-legend.mjs";
10
11
  import { LiquidEditor } from "../../internal/LiquidEditor/LiquidEditor.mjs";
11
12
  import { FieldSectionEnumeration } from "../field-section-enumeration.mjs";
@@ -40,7 +41,19 @@ const EMPTY_CONDITION = {
40
41
  value: ""
41
42
  };
42
43
  const CONNECTOR_GAP = 32;
43
- function ConditionRow({ condition, index, eligibleFields, fieldsByName, isFirst, isLast, logic, form, conditionsPath, fieldNameMode, fieldNamePlaceholder, showStatusProperty, inputFields, searchSecrets, searchConstants, onUpdate, onRemove, onAddCondition, onLogicChange }) {
44
+ /**
45
+ * Maps a fetched field-name suggestion's `data.type` (stringly, from
46
+ * `sheetColumnsOptionsDef`) to an operator list. Unknown/dynamic/json types
47
+ * return `undefined` — callers keep the FULL operator set, since a free-typed
48
+ * column name must never be hard-restricted.
49
+ */
50
+ function operatorsForSuggestion(suggestion) {
51
+ const type = suggestion?.data?.type;
52
+ if (!type || !(type in OPERATORS_BY_TYPE)) return void 0;
53
+ const operators = OPERATORS_BY_TYPE[type];
54
+ return operators.length > 0 ? operators : void 0;
55
+ }
56
+ function ConditionRow({ condition, index, eligibleFields, fieldsByName, isFirst, isLast, logic, form, conditionsPath, fieldNameMode, fieldNamePlaceholder, fieldNameSuggestions, showStatusProperty, inputFields, searchSecrets, searchConstants, onUpdate, onRemove, onAddCondition, onLogicChange }) {
44
57
  const conditionPath = `${conditionsPath}.${index}`;
45
58
  const valueError = useFieldError(form, `${conditionPath}.value`);
46
59
  const fieldNameError = useFieldError(form, `${conditionPath}.field_name`);
@@ -50,6 +63,11 @@ function ConditionRow({ condition, index, eligibleFields, fieldsByName, isFirst,
50
63
  const isTextMode = fieldNameMode === "text";
51
64
  const hasEligibleFields = eligibleFields.length > 0;
52
65
  const selectedField = condition.field_name ? fieldsByName.get(condition.field_name) : void 0;
66
+ const matchedSuggestion = useMemo(() => isTextMode && condition.field_name ? fieldNameSuggestions?.find((s) => s.value === condition.field_name) : void 0, [
67
+ isTextMode,
68
+ condition.field_name,
69
+ fieldNameSuggestions
70
+ ]);
53
71
  const availableOperators = useMemo(() => {
54
72
  if (condition.property === "status") return RUN_IF_STATUS_OPERATORS.map((op) => ({
55
73
  value: op,
@@ -59,13 +77,17 @@ function ConditionRow({ condition, index, eligibleFields, fieldsByName, isFirst,
59
77
  value: op,
60
78
  label: RUN_IF_OPERATOR_LABELS[op]
61
79
  }));
62
- if (isTextMode) return valueOperators;
80
+ if (isTextMode) {
81
+ const suggested = operatorsForSuggestion(matchedSuggestion);
82
+ return suggested ? valueOperators.filter((op) => suggested.includes(op.value)) : valueOperators;
83
+ }
63
84
  if (!selectedField?.type) return [];
64
85
  return valueOperators.filter((op) => OPERATORS_BY_TYPE[selectedField.type].includes(op.value));
65
86
  }, [
66
87
  condition.property,
67
88
  selectedField,
68
- isTextMode
89
+ isTextMode,
90
+ matchedSuggestion
69
91
  ]);
70
92
  const renderValueInput = () => {
71
93
  if (!isTextMode && (!condition.field_name || !selectedField)) return /* @__PURE__ */ jsx(Input, {
@@ -224,7 +246,31 @@ function ConditionRow({ condition, index, eligibleFields, fieldsByName, isFirst,
224
246
  index,
225
247
  onRemove
226
248
  }),
227
- isTextMode ? /* @__PURE__ */ jsx(Input, {
249
+ isTextMode ? fieldNameSuggestions && fieldNameSuggestions.length > 0 ? /* @__PURE__ */ jsx("div", {
250
+ className: "pz:min-w-40",
251
+ children: /* @__PURE__ */ jsx(SuggestCombobox, {
252
+ single: true,
253
+ value: condition.field_name ? [condition.field_name] : [],
254
+ onChange: (next) => {
255
+ const fieldName = next[next.length - 1] ?? "";
256
+ const suggested = operatorsForSuggestion(fieldNameSuggestions.find((s) => s.value === fieldName));
257
+ const operatorStillValid = !suggested || suggested.includes(condition.operator);
258
+ onUpdate(index, {
259
+ ...condition,
260
+ field_name: fieldName,
261
+ ...operatorStillValid ? {} : {
262
+ operator: "eq",
263
+ value: ""
264
+ }
265
+ });
266
+ },
267
+ options: fieldNameSuggestions,
268
+ allowCreate: true,
269
+ ariaInvalid: !!fieldNameError,
270
+ placeholder: fieldNamePlaceholder ?? "column",
271
+ emptyLabel: "No columns found"
272
+ })
273
+ }) : /* @__PURE__ */ jsx(Input, {
228
274
  className: "pz:w-40",
229
275
  "aria-invalid": !!fieldNameError,
230
276
  value: condition.field_name,
@@ -332,7 +378,7 @@ function ConditionRow({ condition, index, eligibleFields, fieldsByName, isFirst,
332
378
  * Operates on a bare `{logic, conditions}` block via `value`/`onChange`; the
333
379
  * wrapping adapters own where that block lives in their payload.
334
380
  */
335
- function ConditionBlockEditor({ value, onChange, fields, form, conditionsPath, fieldNameMode = "select", fieldNamePlaceholder, properties, inputFields, searchSecrets, searchConstants }) {
381
+ function ConditionBlockEditor({ value, onChange, fields, form, conditionsPath, fieldNameMode = "select", fieldNamePlaceholder, fieldNameSuggestions, properties, inputFields, searchSecrets, searchConstants }) {
336
382
  const eligibleFields = useMemo(() => fields.filter((f) => OPERATORS_BY_TYPE[f.type].length > 0), [fields]);
337
383
  const fieldsByName = useMemo(() => new Map(fields.map((f) => [f.fieldName, f])), [fields]);
338
384
  const addBlock = useCallback(() => {
@@ -401,6 +447,7 @@ function ConditionBlockEditor({ value, onChange, fields, form, conditionsPath, f
401
447
  conditionsPath,
402
448
  fieldNameMode,
403
449
  fieldNamePlaceholder,
450
+ fieldNameSuggestions,
404
451
  showStatusProperty: (properties ?? ["value", "status"]).includes("status"),
405
452
  inputFields,
406
453
  searchSecrets,
@@ -441,6 +488,7 @@ function ConditionBlockInputAdapter(field) {
441
488
  conditionsPath: `${field.path}.conditions`,
442
489
  fieldNameMode: meta.fieldNameMode,
443
490
  fieldNamePlaceholder: meta.fieldNamePlaceholder,
491
+ fieldNameSuggestions: meta.options,
444
492
  properties: meta.properties,
445
493
  inputFields: meta.inputFields,
446
494
  searchSecrets: field.searchSecrets,
@@ -1 +1 @@
1
- {"version":3,"file":"pipes-run-if-input.mjs","names":[],"sources":["../../../../src/components/defaults/adapters/pipes-run-if-input.tsx"],"sourcesContent":["import {\n type ConditionBlockMeta,\n type ConditionOperators,\n type ConstantSuggestion,\n type PipeRunIf,\n type PipesFieldDefinitionWithName,\n type PipesRunIfMeta,\n type RecordFieldType,\n RUN_IF_OPERATOR_LABELS,\n RUN_IF_STATUS_OPERATORS,\n RUN_IF_VALUE_OPERATORS,\n type SecretSuggestion,\n} from \"@pipe0/base\";\nimport { useCallback, useMemo } from \"react\";\nimport { useFieldError } from \"../../../hooks/use-field-error.js\";\nimport { cn } from \"../../../lib/utils.js\";\nimport type { FieldHandle } from \"../../../types/field-handle.js\";\nimport type { FormHandle } from \"../../../types/form-handle.js\";\nimport { HoverInfo } from \"../../hover-info.js\";\nimport { FieldLegend } from \"../../internal/field-legend.js\";\nimport { IconPlus } from \"../../internal/icons.js\";\nimport { LiquidEditor } from \"../../internal/LiquidEditor/LiquidEditor.js\";\nimport { Badge } from \"../../ui/badge.js\";\nimport { Button } from \"../../ui/button.js\";\nimport { Input } from \"../../ui/input.js\";\nimport {\n Select,\n SelectContent,\n SelectGroup,\n SelectItem,\n SelectTrigger,\n SelectValue,\n} from \"../../ui/select.js\";\nimport { FieldSectionEnumeration } from \"../field-section-enumeration.js\";\n\n// Use a loose type for internal manipulation since the discriminated union\n// is strict about property/operator/value combinations.\ntype Condition = {\n field_name: string;\n property: string;\n operator: string;\n value: unknown;\n};\n\n// Loose shape of a bare condition block ({logic, conditions}) — the run-if\n// `when` block, and an effect's `config.where`. The editor below is shared by\n// both; the strict discriminated-union types live in @pipe0/base.\ntype ConditionBlockValue = {\n logic: \"and\" | \"or\";\n conditions: Condition[];\n};\n\nconst OPERATORS_BY_TYPE: Record<RecordFieldType, ConditionOperators[]> = {\n string: [\"eq\", \"neq\", \"contains\", \"matches\"],\n number: [\"eq\", \"neq\", \"gt\", \"gte\", \"lt\", \"lte\"],\n boolean: [\"eq\", \"neq\"],\n json: [],\n unknown: [],\n};\n\nconst EMPTY_CONDITION: Condition = {\n field_name: \"\",\n property: \"value\",\n operator: \"eq\",\n value: \"\",\n};\n\nconst CONNECTOR_GAP = 32;\n\ntype MetaField = {\n fieldName: string;\n fieldLabel: string;\n type: RecordFieldType;\n format: string | null;\n};\n\nfunction ConditionRow({\n condition,\n index,\n eligibleFields,\n fieldsByName,\n isFirst,\n isLast,\n logic,\n form,\n conditionsPath,\n fieldNameMode,\n fieldNamePlaceholder,\n showStatusProperty,\n inputFields,\n searchSecrets,\n searchConstants,\n onUpdate,\n onRemove,\n onAddCondition,\n onLogicChange,\n}: {\n condition: Condition;\n index: number;\n eligibleFields: MetaField[];\n fieldsByName: ReadonlyMap<string, MetaField>;\n isFirst: boolean;\n isLast: boolean;\n logic: PipeRunIf[\"when\"][\"logic\"];\n form: FormHandle;\n conditionsPath: string;\n fieldNameMode: \"select\" | \"text\";\n fieldNamePlaceholder?: string;\n showStatusProperty: boolean;\n inputFields?: PipesFieldDefinitionWithName[];\n searchSecrets?: (query: string) => Promise<SecretSuggestion[]>;\n searchConstants?: (query: string) => Promise<ConstantSuggestion[]>;\n onUpdate: (index: number, condition: Condition) => void;\n onRemove: (index: number) => void;\n onAddCondition: () => void;\n onLogicChange: (logic: PipeRunIf[\"when\"][\"logic\"]) => void;\n}) {\n const conditionPath = `${conditionsPath}.${index}`;\n const valueError = useFieldError(form, `${conditionPath}.value`);\n const fieldNameError = useFieldError(form, `${conditionPath}.field_name`);\n const operatorError = useFieldError(form, `${conditionPath}.operator`);\n const propertyError = useFieldError(form, `${conditionPath}.property`);\n\n const showConnector = !(isFirst && isLast);\n const isTextMode = fieldNameMode === \"text\";\n const hasEligibleFields = eligibleFields.length > 0;\n const selectedField = condition.field_name ? fieldsByName.get(condition.field_name) : undefined;\n\n const availableOperators = useMemo(() => {\n if (condition.property === \"status\") {\n return RUN_IF_STATUS_OPERATORS.map((op) => ({\n value: op,\n label: RUN_IF_OPERATOR_LABELS[op],\n }));\n }\n const valueOperators = RUN_IF_VALUE_OPERATORS.map((op) => ({\n value: op,\n label: RUN_IF_OPERATOR_LABELS[op],\n }));\n // Free-text field names target a sheet whose column types are unknown —\n // offer the full operator set.\n if (isTextMode) return valueOperators;\n if (!selectedField?.type) return [];\n return valueOperators.filter((op) => OPERATORS_BY_TYPE[selectedField.type].includes(op.value));\n }, [condition.property, selectedField, isTextMode]);\n\n const renderValueInput = () => {\n if (!isTextMode && (!condition.field_name || !selectedField)) {\n return <Input className=\"pz:w-32\" placeholder=\"\" disabled aria-invalid={!!valueError} />;\n }\n\n if (isTextMode && condition.property !== \"status\") {\n if (inputFields) {\n return (\n <div\n className={cn(\n \"pz:w-64 pz:rounded-md pz:border pz:border-input pz:bg-transparent\",\n valueError && \"pz:border-destructive\",\n )}\n >\n <LiquidEditor\n value={String(condition.value ?? \"\")}\n onChange={(v) => onUpdate(index, { ...condition, value: v })}\n inputFields={inputFields}\n searchSecrets={searchSecrets}\n searchConstants={searchConstants}\n placeholder=\"\"\n hideLegend\n />\n </div>\n );\n }\n return (\n <Input\n className=\"pz:w-32\"\n aria-invalid={!!valueError}\n value={String(condition.value ?? \"\")}\n onChange={(e) => onUpdate(index, { ...condition, value: e.target.value })}\n placeholder=\"\"\n />\n );\n }\n\n if (condition.property === \"status\") {\n return (\n <Select\n value={String(condition.value) || null}\n onValueChange={(v) => onUpdate(index, { ...condition, value: v })}\n >\n <SelectTrigger className=\"pz:w-32\" aria-invalid={!!valueError}>\n <SelectValue placeholder=\"--status--\" />\n </SelectTrigger>\n <SelectContent>\n <SelectItem value=\"completed\">completed</SelectItem>\n <SelectItem value=\"skipped\">skipped</SelectItem>\n <SelectItem value=\"failed\">failed</SelectItem>\n <SelectItem value=\"no_result\">no_result</SelectItem>\n </SelectContent>\n </Select>\n );\n }\n\n if (selectedField?.type === \"boolean\") {\n return (\n <Select\n value={String(condition.value)}\n onValueChange={(v) => onUpdate(index, { ...condition, value: v })}\n >\n <SelectTrigger className=\"pz:w-24\" aria-invalid={!!valueError}>\n <SelectValue />\n </SelectTrigger>\n <SelectContent>\n <SelectItem value=\"true\">true</SelectItem>\n <SelectItem value=\"false\">false</SelectItem>\n </SelectContent>\n </Select>\n );\n }\n\n if (selectedField?.type === \"number\") {\n return (\n <Input\n type=\"number\"\n className=\"pz:w-32\"\n aria-invalid={!!valueError}\n value={String(Number(condition.value ?? 0))}\n onChange={(e) =>\n onUpdate(index, {\n ...condition,\n value: Number(e.target.value) || 0,\n })\n }\n placeholder=\"\"\n />\n );\n }\n\n return (\n <Input\n className=\"pz:w-32\"\n aria-invalid={!!valueError}\n value={String(condition.value ?? \"\")}\n onChange={(e) => onUpdate(index, { ...condition, value: e.target.value })}\n placeholder=\"\"\n />\n );\n };\n\n const errorMessage = valueError || fieldNameError || operatorError || propertyError;\n\n return (\n <div>\n <div className={cn(\"pz:relative\", showConnector && \"pz:pl-17\")}>\n {showConnector && (\n <>\n {isFirst ? (\n <div\n className=\"pz:absolute pz:left-7 pz:w-10 pz:border-l-2 pz:border-t-2 pz:border-input pz:rounded-tl-lg pz:pointer-events-none\"\n style={{ top: \"50%\", bottom: -CONNECTOR_GAP }}\n />\n ) : (\n <div\n className=\"pz:absolute pz:left-7 pz:w-10 pz:border-l-2 pz:border-b-2 pz:border-input pz:rounded-bl-lg pz:pointer-events-none\"\n style={{ top: -CONNECTOR_GAP, bottom: \"50%\" }}\n />\n )}\n {!isFirst && !isLast && (\n <div\n className=\"pz:absolute pz:left-7 pz:border-l-2 pz:border-input pz:pointer-events-none\"\n style={{ top: \"50%\", bottom: -CONNECTOR_GAP }}\n />\n )}\n {!isFirst && (\n <div\n className=\"pz:absolute pz:left-7 pz:z-10\"\n style={{\n top: -CONNECTOR_GAP / 2,\n transform: \"translate(-50%, -50%)\",\n }}\n >\n <Select value={logic} onValueChange={(v) => onLogicChange(v as \"and\" | \"or\")}>\n <SelectTrigger className=\"pz:w-17 pz:h-6 pz:text-xs pz:bg-background pz:hover:bg-accent\">\n <SelectValue />\n </SelectTrigger>\n <SelectContent>\n <SelectGroup>\n <SelectItem value=\"and\">AND</SelectItem>\n <SelectItem value=\"or\">OR</SelectItem>\n </SelectGroup>\n </SelectContent>\n </Select>\n </div>\n )}\n </>\n )}\n <div className=\"pz:flex pz:flex-wrap pz:items-center pz:gap-2\">\n <FieldSectionEnumeration index={index} onRemove={onRemove} />\n {isTextMode ? (\n <Input\n className=\"pz:w-40\"\n aria-invalid={!!fieldNameError}\n value={condition.field_name}\n onChange={(e) => onUpdate(index, { ...condition, field_name: e.target.value })}\n placeholder={fieldNamePlaceholder ?? \"column\"}\n />\n ) : (\n <>\n <Select\n value={condition.field_name || null}\n disabled={!hasEligibleFields}\n onValueChange={(v) => {\n if (v === null) return;\n onUpdate(index, {\n ...condition,\n field_name: v,\n operator: \"eq\",\n value: \"\",\n });\n }}\n >\n <SelectTrigger className=\"pz:w-40\" aria-invalid={!!fieldNameError}>\n <SelectValue placeholder=\"Select field\" />\n </SelectTrigger>\n <SelectContent>\n {eligibleFields.map((f) => (\n <SelectItem key={f.fieldName} value={f.fieldName}>\n {f.fieldLabel || f.fieldName}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n {!hasEligibleFields && (\n <span className=\"pz:text-xs pz:text-muted-foreground\">\n No fields available{\" \"}\n <HoverInfo>\n Conditions require plain fields. JSON fields are not allowed.\n </HoverInfo>\n </span>\n )}\n </>\n )}\n\n {(isTextMode || selectedField?.type) && (\n <>\n {showStatusProperty && (\n <>\n <Badge\n variant=\"secondary\"\n className=\"pz:bg-accent pz:border pz:border-input pz:font-normal pz:text-muted-foreground pz:h-8\"\n >\n &apos;s\n </Badge>\n <Select\n defaultValue=\"value\"\n value={condition.property}\n onValueChange={(v) => {\n if (v === null) return;\n onUpdate(index, {\n ...condition,\n property: v,\n operator: \"eq\",\n value: \"\",\n });\n }}\n >\n <SelectTrigger className=\"pz:w-28\" aria-invalid={!!propertyError}>\n <SelectValue />\n </SelectTrigger>\n <SelectContent>\n <SelectItem value=\"value\">value</SelectItem>\n <SelectItem value=\"status\">status</SelectItem>\n </SelectContent>\n </Select>\n </>\n )}\n\n <Select\n value={condition.operator}\n onValueChange={(v) =>\n onUpdate(index, {\n ...condition,\n operator: v as ConditionOperators,\n })\n }\n >\n <SelectTrigger className=\"pz:w-28\" aria-invalid={!!operatorError}>\n <SelectValue />\n </SelectTrigger>\n <SelectContent>\n {availableOperators.map((op) => (\n <SelectItem key={op.value} value={op.value}>\n {op.label}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n\n {renderValueInput()}\n </>\n )}\n </div>\n {errorMessage && (\n <span\n className=\"pz:text-destructive pz:text-xs pz:font-medium pz:mt-1 pz:block\"\n role=\"alert\"\n >\n {errorMessage}\n </span>\n )}\n </div>\n {isLast && (\n <div className=\"pz:flex pz:items-center pz:gap-2\">\n <Button type=\"button\" variant=\"link\" size=\"xs\" onClick={onAddCondition}>\n <IconPlus />\n New rule\n </Button>\n </div>\n )}\n </div>\n );\n}\n\n/**\n * Presentational condition-block editor shared by the pipe run-if gate and by\n * effects that filter rows by a condition (e.g. `rows:remove@1`'s `where`).\n * Operates on a bare `{logic, conditions}` block via `value`/`onChange`; the\n * wrapping adapters own where that block lives in their payload.\n */\nexport function ConditionBlockEditor({\n value,\n onChange,\n fields,\n form,\n conditionsPath,\n fieldNameMode = \"select\",\n fieldNamePlaceholder,\n properties,\n inputFields,\n searchSecrets,\n searchConstants,\n}: {\n value: ConditionBlockValue | null;\n onChange: (value: ConditionBlockValue | null) => void;\n fields: MetaField[];\n form: FormHandle;\n // Field-error path of the conditions array (e.g. `run_if.when.conditions` or\n // `config.where.conditions`).\n conditionsPath: string;\n // \"text\" renders field_name as a free-form column name (the condition\n // targets a sheet whose columns are unknown at config time).\n fieldNameMode?: \"select\" | \"text\";\n fieldNamePlaceholder?: string;\n // Which condition properties are offered; defaults to value + status.\n properties?: (\"value\" | \"status\")[];\n // When present, string values render a LiquidEditor with the `/` picker.\n inputFields?: PipesFieldDefinitionWithName[];\n searchSecrets?: (query: string) => Promise<SecretSuggestion[]>;\n searchConstants?: (query: string) => Promise<ConstantSuggestion[]>;\n}) {\n // Built once and reused across every condition row, instead of each row\n // scanning `fields` linearly. With N rows and M fields this turns O(N·M)\n // lookups into O(N+M).\n const eligibleFields = useMemo(\n () => fields.filter((f) => OPERATORS_BY_TYPE[f.type].length > 0),\n [fields],\n );\n const fieldsByName = useMemo(() => new Map(fields.map((f) => [f.fieldName, f])), [fields]);\n\n const addBlock = useCallback(() => {\n onChange({ logic: \"and\", conditions: [{ ...EMPTY_CONDITION }] });\n }, [onChange]);\n\n const updateCondition = (index: number, condition: Condition) => {\n if (!value) return;\n const newConditions = [...value.conditions];\n newConditions[index] = condition;\n onChange({ ...value, conditions: newConditions });\n };\n\n const removeCondition = (index: number) => {\n if (!value) return;\n if (value.conditions.length <= 1) {\n onChange(null);\n return;\n }\n onChange({ ...value, conditions: value.conditions.filter((_, i) => i !== index) });\n };\n\n const addCondition = () => {\n if (!value) return;\n onChange({ ...value, conditions: [...value.conditions, { ...EMPTY_CONDITION }] });\n };\n\n const changeLogic = (logic: \"and\" | \"or\") => {\n if (!value) return;\n onChange({ ...value, logic });\n };\n\n return (\n <div data-p0=\"input\">\n {!value ? (\n <div className=\"pz:flex pz:items-center\">\n <Button type=\"button\" variant=\"link\" size=\"xs\" className=\"pz:px-0\" onClick={addBlock}>\n <IconPlus />\n New rule\n </Button>\n </div>\n ) : (\n <div className=\"pz:flex pz:flex-col pz:gap-8\">\n {value.conditions.map((condition, idx) => (\n <ConditionRow\n key={idx}\n condition={condition}\n index={idx}\n eligibleFields={eligibleFields}\n fieldsByName={fieldsByName}\n isFirst={idx === 0}\n isLast={idx === value.conditions.length - 1}\n logic={value.logic}\n form={form}\n conditionsPath={conditionsPath}\n fieldNameMode={fieldNameMode}\n fieldNamePlaceholder={fieldNamePlaceholder}\n showStatusProperty={(properties ?? [\"value\", \"status\"]).includes(\"status\")}\n inputFields={inputFields}\n searchSecrets={searchSecrets}\n searchConstants={searchConstants}\n onUpdate={updateCondition}\n onRemove={removeCondition}\n onAddCondition={addCondition}\n onLogicChange={changeLogic}\n />\n ))}\n {fieldNameMode === \"text\" && inputFields && (\n <FieldLegend entries={[{ key: \"/\", label: \"to insert a reference\" }]} />\n )}\n </div>\n )}\n </div>\n );\n}\n\nexport function PipesRunIfInputAdapter(field: FieldHandle<\"pipes_run_if_input\">) {\n const pipeRunIf = field.value as PipeRunIf | null;\n const meta = field.meta as PipesRunIfMeta;\n\n return (\n <ConditionBlockEditor\n value={(pipeRunIf?.when as ConditionBlockValue | undefined) ?? null}\n onChange={(block) => field.setValue(block ? { action: \"run\", when: block } : null)}\n fields={meta.fields}\n form={field.form}\n conditionsPath={`${field.path}.when.conditions`}\n />\n );\n}\n\nexport function ConditionBlockInputAdapter(field: FieldHandle<\"condition_block_input\">) {\n const block = field.value as ConditionBlockValue | null;\n const meta = field.meta as ConditionBlockMeta;\n\n return (\n <ConditionBlockEditor\n value={block}\n onChange={(next) => field.setValue(next)}\n fields={meta.fields}\n form={field.form}\n conditionsPath={`${field.path}.conditions`}\n fieldNameMode={meta.fieldNameMode}\n fieldNamePlaceholder={meta.fieldNamePlaceholder}\n properties={meta.properties}\n inputFields={meta.inputFields}\n searchSecrets={field.searchSecrets}\n searchConstants={field.searchConstants}\n />\n );\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"pipes-run-if-input.mjs","names":[],"sources":["../../../../src/components/defaults/adapters/pipes-run-if-input.tsx"],"sourcesContent":["import {\n type ConditionBlockMeta,\n type ConditionOperators,\n type ConstantSuggestion,\n type PipeRunIf,\n type PipesFieldDefinitionWithName,\n type PipesRunIfMeta,\n type RecordFieldType,\n RUN_IF_OPERATOR_LABELS,\n RUN_IF_STATUS_OPERATORS,\n RUN_IF_VALUE_OPERATORS,\n type SecretSuggestion,\n type StoreOption,\n} from \"@pipe0/base\";\nimport { useCallback, useMemo } from \"react\";\nimport { useFieldError } from \"../../../hooks/use-field-error.js\";\nimport { cn } from \"../../../lib/utils.js\";\nimport type { FieldHandle } from \"../../../types/field-handle.js\";\nimport type { FormHandle } from \"../../../types/form-handle.js\";\nimport { HoverInfo } from \"../../hover-info.js\";\nimport { SuggestCombobox } from \"../../internal/combobox/suggest-combobox.js\";\nimport { FieldLegend } from \"../../internal/field-legend.js\";\nimport { IconPlus } from \"../../internal/icons.js\";\nimport { LiquidEditor } from \"../../internal/LiquidEditor/LiquidEditor.js\";\nimport { Badge } from \"../../ui/badge.js\";\nimport { Button } from \"../../ui/button.js\";\nimport { Input } from \"../../ui/input.js\";\nimport {\n Select,\n SelectContent,\n SelectGroup,\n SelectItem,\n SelectTrigger,\n SelectValue,\n} from \"../../ui/select.js\";\nimport { FieldSectionEnumeration } from \"../field-section-enumeration.js\";\n\n// Use a loose type for internal manipulation since the discriminated union\n// is strict about property/operator/value combinations.\ntype Condition = {\n field_name: string;\n property: string;\n operator: string;\n value: unknown;\n};\n\n// Loose shape of a bare condition block ({logic, conditions}) — the run-if\n// `when` block, and an effect's `config.where`. The editor below is shared by\n// both; the strict discriminated-union types live in @pipe0/base.\ntype ConditionBlockValue = {\n logic: \"and\" | \"or\";\n conditions: Condition[];\n};\n\nconst OPERATORS_BY_TYPE: Record<RecordFieldType, ConditionOperators[]> = {\n string: [\"eq\", \"neq\", \"contains\", \"matches\"],\n number: [\"eq\", \"neq\", \"gt\", \"gte\", \"lt\", \"lte\"],\n boolean: [\"eq\", \"neq\"],\n json: [],\n unknown: [],\n};\n\nconst EMPTY_CONDITION: Condition = {\n field_name: \"\",\n property: \"value\",\n operator: \"eq\",\n value: \"\",\n};\n\nconst CONNECTOR_GAP = 32;\n\n/**\n * Maps a fetched field-name suggestion's `data.type` (stringly, from\n * `sheetColumnsOptionsDef`) to an operator list. Unknown/dynamic/json types\n * return `undefined` — callers keep the FULL operator set, since a free-typed\n * column name must never be hard-restricted.\n */\nfunction operatorsForSuggestion(\n suggestion: StoreOption | undefined,\n): ConditionOperators[] | undefined {\n const type = suggestion?.data?.type;\n if (!type || !(type in OPERATORS_BY_TYPE)) return undefined;\n const operators = OPERATORS_BY_TYPE[type as RecordFieldType];\n return operators.length > 0 ? operators : undefined;\n}\n\ntype MetaField = {\n fieldName: string;\n fieldLabel: string;\n type: RecordFieldType;\n format: string | null;\n};\n\nfunction ConditionRow({\n condition,\n index,\n eligibleFields,\n fieldsByName,\n isFirst,\n isLast,\n logic,\n form,\n conditionsPath,\n fieldNameMode,\n fieldNamePlaceholder,\n fieldNameSuggestions,\n showStatusProperty,\n inputFields,\n searchSecrets,\n searchConstants,\n onUpdate,\n onRemove,\n onAddCondition,\n onLogicChange,\n}: {\n condition: Condition;\n index: number;\n eligibleFields: MetaField[];\n fieldsByName: ReadonlyMap<string, MetaField>;\n isFirst: boolean;\n isLast: boolean;\n logic: PipeRunIf[\"when\"][\"logic\"];\n form: FormHandle;\n conditionsPath: string;\n fieldNameMode: \"select\" | \"text\";\n fieldNamePlaceholder?: string;\n /** Fetched `field_name` suggestions (text mode) — upgrades the free-text input to a combobox. */\n fieldNameSuggestions?: StoreOption[];\n showStatusProperty: boolean;\n inputFields?: PipesFieldDefinitionWithName[];\n searchSecrets?: (query: string) => Promise<SecretSuggestion[]>;\n searchConstants?: (query: string) => Promise<ConstantSuggestion[]>;\n onUpdate: (index: number, condition: Condition) => void;\n onRemove: (index: number) => void;\n onAddCondition: () => void;\n onLogicChange: (logic: PipeRunIf[\"when\"][\"logic\"]) => void;\n}) {\n const conditionPath = `${conditionsPath}.${index}`;\n const valueError = useFieldError(form, `${conditionPath}.value`);\n const fieldNameError = useFieldError(form, `${conditionPath}.field_name`);\n const operatorError = useFieldError(form, `${conditionPath}.operator`);\n const propertyError = useFieldError(form, `${conditionPath}.property`);\n\n const showConnector = !(isFirst && isLast);\n const isTextMode = fieldNameMode === \"text\";\n const hasEligibleFields = eligibleFields.length > 0;\n const selectedField = condition.field_name ? fieldsByName.get(condition.field_name) : undefined;\n\n const matchedSuggestion = useMemo(\n () =>\n isTextMode && condition.field_name\n ? fieldNameSuggestions?.find((s) => s.value === condition.field_name)\n : undefined,\n [isTextMode, condition.field_name, fieldNameSuggestions],\n );\n\n const availableOperators = useMemo(() => {\n if (condition.property === \"status\") {\n return RUN_IF_STATUS_OPERATORS.map((op) => ({\n value: op,\n label: RUN_IF_OPERATOR_LABELS[op],\n }));\n }\n const valueOperators = RUN_IF_VALUE_OPERATORS.map((op) => ({\n value: op,\n label: RUN_IF_OPERATOR_LABELS[op],\n }));\n if (isTextMode) {\n // Free-text field names target a sheet whose column types are unknown —\n // offer the full operator set, narrowed only when the typed name matches\n // a fetched suggestion with a known type.\n const suggested = operatorsForSuggestion(matchedSuggestion);\n return suggested\n ? valueOperators.filter((op) => suggested.includes(op.value))\n : valueOperators;\n }\n if (!selectedField?.type) return [];\n return valueOperators.filter((op) => OPERATORS_BY_TYPE[selectedField.type].includes(op.value));\n }, [condition.property, selectedField, isTextMode, matchedSuggestion]);\n\n const renderValueInput = () => {\n if (!isTextMode && (!condition.field_name || !selectedField)) {\n return <Input className=\"pz:w-32\" placeholder=\"\" disabled aria-invalid={!!valueError} />;\n }\n\n if (isTextMode && condition.property !== \"status\") {\n if (inputFields) {\n return (\n <div\n className={cn(\n \"pz:w-64 pz:rounded-md pz:border pz:border-input pz:bg-transparent\",\n valueError && \"pz:border-destructive\",\n )}\n >\n <LiquidEditor\n value={String(condition.value ?? \"\")}\n onChange={(v) => onUpdate(index, { ...condition, value: v })}\n inputFields={inputFields}\n searchSecrets={searchSecrets}\n searchConstants={searchConstants}\n placeholder=\"\"\n hideLegend\n />\n </div>\n );\n }\n return (\n <Input\n className=\"pz:w-32\"\n aria-invalid={!!valueError}\n value={String(condition.value ?? \"\")}\n onChange={(e) => onUpdate(index, { ...condition, value: e.target.value })}\n placeholder=\"\"\n />\n );\n }\n\n if (condition.property === \"status\") {\n return (\n <Select\n value={String(condition.value) || null}\n onValueChange={(v) => onUpdate(index, { ...condition, value: v })}\n >\n <SelectTrigger className=\"pz:w-32\" aria-invalid={!!valueError}>\n <SelectValue placeholder=\"--status--\" />\n </SelectTrigger>\n <SelectContent>\n <SelectItem value=\"completed\">completed</SelectItem>\n <SelectItem value=\"skipped\">skipped</SelectItem>\n <SelectItem value=\"failed\">failed</SelectItem>\n <SelectItem value=\"no_result\">no_result</SelectItem>\n </SelectContent>\n </Select>\n );\n }\n\n if (selectedField?.type === \"boolean\") {\n return (\n <Select\n value={String(condition.value)}\n onValueChange={(v) => onUpdate(index, { ...condition, value: v })}\n >\n <SelectTrigger className=\"pz:w-24\" aria-invalid={!!valueError}>\n <SelectValue />\n </SelectTrigger>\n <SelectContent>\n <SelectItem value=\"true\">true</SelectItem>\n <SelectItem value=\"false\">false</SelectItem>\n </SelectContent>\n </Select>\n );\n }\n\n if (selectedField?.type === \"number\") {\n return (\n <Input\n type=\"number\"\n className=\"pz:w-32\"\n aria-invalid={!!valueError}\n value={String(Number(condition.value ?? 0))}\n onChange={(e) =>\n onUpdate(index, {\n ...condition,\n value: Number(e.target.value) || 0,\n })\n }\n placeholder=\"\"\n />\n );\n }\n\n return (\n <Input\n className=\"pz:w-32\"\n aria-invalid={!!valueError}\n value={String(condition.value ?? \"\")}\n onChange={(e) => onUpdate(index, { ...condition, value: e.target.value })}\n placeholder=\"\"\n />\n );\n };\n\n const errorMessage = valueError || fieldNameError || operatorError || propertyError;\n\n return (\n <div>\n <div className={cn(\"pz:relative\", showConnector && \"pz:pl-17\")}>\n {showConnector && (\n <>\n {isFirst ? (\n <div\n className=\"pz:absolute pz:left-7 pz:w-10 pz:border-l-2 pz:border-t-2 pz:border-input pz:rounded-tl-lg pz:pointer-events-none\"\n style={{ top: \"50%\", bottom: -CONNECTOR_GAP }}\n />\n ) : (\n <div\n className=\"pz:absolute pz:left-7 pz:w-10 pz:border-l-2 pz:border-b-2 pz:border-input pz:rounded-bl-lg pz:pointer-events-none\"\n style={{ top: -CONNECTOR_GAP, bottom: \"50%\" }}\n />\n )}\n {!isFirst && !isLast && (\n <div\n className=\"pz:absolute pz:left-7 pz:border-l-2 pz:border-input pz:pointer-events-none\"\n style={{ top: \"50%\", bottom: -CONNECTOR_GAP }}\n />\n )}\n {!isFirst && (\n <div\n className=\"pz:absolute pz:left-7 pz:z-10\"\n style={{\n top: -CONNECTOR_GAP / 2,\n transform: \"translate(-50%, -50%)\",\n }}\n >\n <Select value={logic} onValueChange={(v) => onLogicChange(v as \"and\" | \"or\")}>\n <SelectTrigger className=\"pz:w-17 pz:h-6 pz:text-xs pz:bg-background pz:hover:bg-accent\">\n <SelectValue />\n </SelectTrigger>\n <SelectContent>\n <SelectGroup>\n <SelectItem value=\"and\">AND</SelectItem>\n <SelectItem value=\"or\">OR</SelectItem>\n </SelectGroup>\n </SelectContent>\n </Select>\n </div>\n )}\n </>\n )}\n <div className=\"pz:flex pz:flex-wrap pz:items-center pz:gap-2\">\n <FieldSectionEnumeration index={index} onRemove={onRemove} />\n {isTextMode ? (\n fieldNameSuggestions && fieldNameSuggestions.length > 0 ? (\n // Fetched target-sheet columns available → suggest combobox.\n // `allowCreate` keeps any literal column name typeable.\n <div className=\"pz:min-w-40\">\n <SuggestCombobox\n single\n value={condition.field_name ? [condition.field_name] : []}\n onChange={(next) => {\n const fieldName = next[next.length - 1] ?? \"\";\n const suggested = operatorsForSuggestion(\n fieldNameSuggestions.find((s) => s.value === fieldName),\n );\n const operatorStillValid =\n !suggested || suggested.includes(condition.operator as ConditionOperators);\n onUpdate(index, {\n ...condition,\n field_name: fieldName,\n ...(operatorStillValid ? {} : { operator: \"eq\", value: \"\" }),\n });\n }}\n options={fieldNameSuggestions}\n allowCreate\n ariaInvalid={!!fieldNameError}\n placeholder={fieldNamePlaceholder ?? \"column\"}\n emptyLabel=\"No columns found\"\n />\n </div>\n ) : (\n <Input\n className=\"pz:w-40\"\n aria-invalid={!!fieldNameError}\n value={condition.field_name}\n onChange={(e) => onUpdate(index, { ...condition, field_name: e.target.value })}\n placeholder={fieldNamePlaceholder ?? \"column\"}\n />\n )\n ) : (\n <>\n <Select\n value={condition.field_name || null}\n disabled={!hasEligibleFields}\n onValueChange={(v) => {\n if (v === null) return;\n onUpdate(index, {\n ...condition,\n field_name: v,\n operator: \"eq\",\n value: \"\",\n });\n }}\n >\n <SelectTrigger className=\"pz:w-40\" aria-invalid={!!fieldNameError}>\n <SelectValue placeholder=\"Select field\" />\n </SelectTrigger>\n <SelectContent>\n {eligibleFields.map((f) => (\n <SelectItem key={f.fieldName} value={f.fieldName}>\n {f.fieldLabel || f.fieldName}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n {!hasEligibleFields && (\n <span className=\"pz:text-xs pz:text-muted-foreground\">\n No fields available{\" \"}\n <HoverInfo>\n Conditions require plain fields. JSON fields are not allowed.\n </HoverInfo>\n </span>\n )}\n </>\n )}\n\n {(isTextMode || selectedField?.type) && (\n <>\n {showStatusProperty && (\n <>\n <Badge\n variant=\"secondary\"\n className=\"pz:bg-accent pz:border pz:border-input pz:font-normal pz:text-muted-foreground pz:h-8\"\n >\n &apos;s\n </Badge>\n <Select\n defaultValue=\"value\"\n value={condition.property}\n onValueChange={(v) => {\n if (v === null) return;\n onUpdate(index, {\n ...condition,\n property: v,\n operator: \"eq\",\n value: \"\",\n });\n }}\n >\n <SelectTrigger className=\"pz:w-28\" aria-invalid={!!propertyError}>\n <SelectValue />\n </SelectTrigger>\n <SelectContent>\n <SelectItem value=\"value\">value</SelectItem>\n <SelectItem value=\"status\">status</SelectItem>\n </SelectContent>\n </Select>\n </>\n )}\n\n <Select\n value={condition.operator}\n onValueChange={(v) =>\n onUpdate(index, {\n ...condition,\n operator: v as ConditionOperators,\n })\n }\n >\n <SelectTrigger className=\"pz:w-28\" aria-invalid={!!operatorError}>\n <SelectValue />\n </SelectTrigger>\n <SelectContent>\n {availableOperators.map((op) => (\n <SelectItem key={op.value} value={op.value}>\n {op.label}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n\n {renderValueInput()}\n </>\n )}\n </div>\n {errorMessage && (\n <span\n className=\"pz:text-destructive pz:text-xs pz:font-medium pz:mt-1 pz:block\"\n role=\"alert\"\n >\n {errorMessage}\n </span>\n )}\n </div>\n {isLast && (\n <div className=\"pz:flex pz:items-center pz:gap-2\">\n <Button type=\"button\" variant=\"link\" size=\"xs\" onClick={onAddCondition}>\n <IconPlus />\n New rule\n </Button>\n </div>\n )}\n </div>\n );\n}\n\n/**\n * Presentational condition-block editor shared by the pipe run-if gate and by\n * effects that filter rows by a condition (e.g. `rows:remove@1`'s `where`).\n * Operates on a bare `{logic, conditions}` block via `value`/`onChange`; the\n * wrapping adapters own where that block lives in their payload.\n */\nexport function ConditionBlockEditor({\n value,\n onChange,\n fields,\n form,\n conditionsPath,\n fieldNameMode = \"select\",\n fieldNamePlaceholder,\n fieldNameSuggestions,\n properties,\n inputFields,\n searchSecrets,\n searchConstants,\n}: {\n value: ConditionBlockValue | null;\n onChange: (value: ConditionBlockValue | null) => void;\n fields: MetaField[];\n form: FormHandle;\n // Field-error path of the conditions array (e.g. `run_if.when.conditions` or\n // `config.where.conditions`).\n conditionsPath: string;\n // \"text\" renders field_name as a free-form column name (the condition\n // targets a sheet whose columns are unknown at config time).\n fieldNameMode?: \"select\" | \"text\";\n fieldNamePlaceholder?: string;\n // Fetched target-sheet column suggestions (text mode only) — when non-empty\n // the free-text field name upgrades to a suggest combobox.\n fieldNameSuggestions?: StoreOption[];\n // Which condition properties are offered; defaults to value + status.\n properties?: (\"value\" | \"status\")[];\n // When present, string values render a LiquidEditor with the `/` picker.\n inputFields?: PipesFieldDefinitionWithName[];\n searchSecrets?: (query: string) => Promise<SecretSuggestion[]>;\n searchConstants?: (query: string) => Promise<ConstantSuggestion[]>;\n}) {\n // Built once and reused across every condition row, instead of each row\n // scanning `fields` linearly. With N rows and M fields this turns O(N·M)\n // lookups into O(N+M).\n const eligibleFields = useMemo(\n () => fields.filter((f) => OPERATORS_BY_TYPE[f.type].length > 0),\n [fields],\n );\n const fieldsByName = useMemo(() => new Map(fields.map((f) => [f.fieldName, f])), [fields]);\n\n const addBlock = useCallback(() => {\n onChange({ logic: \"and\", conditions: [{ ...EMPTY_CONDITION }] });\n }, [onChange]);\n\n const updateCondition = (index: number, condition: Condition) => {\n if (!value) return;\n const newConditions = [...value.conditions];\n newConditions[index] = condition;\n onChange({ ...value, conditions: newConditions });\n };\n\n const removeCondition = (index: number) => {\n if (!value) return;\n if (value.conditions.length <= 1) {\n onChange(null);\n return;\n }\n onChange({ ...value, conditions: value.conditions.filter((_, i) => i !== index) });\n };\n\n const addCondition = () => {\n if (!value) return;\n onChange({ ...value, conditions: [...value.conditions, { ...EMPTY_CONDITION }] });\n };\n\n const changeLogic = (logic: \"and\" | \"or\") => {\n if (!value) return;\n onChange({ ...value, logic });\n };\n\n return (\n <div data-p0=\"input\">\n {!value ? (\n <div className=\"pz:flex pz:items-center\">\n <Button type=\"button\" variant=\"link\" size=\"xs\" className=\"pz:px-0\" onClick={addBlock}>\n <IconPlus />\n New rule\n </Button>\n </div>\n ) : (\n <div className=\"pz:flex pz:flex-col pz:gap-8\">\n {value.conditions.map((condition, idx) => (\n <ConditionRow\n key={idx}\n condition={condition}\n index={idx}\n eligibleFields={eligibleFields}\n fieldsByName={fieldsByName}\n isFirst={idx === 0}\n isLast={idx === value.conditions.length - 1}\n logic={value.logic}\n form={form}\n conditionsPath={conditionsPath}\n fieldNameMode={fieldNameMode}\n fieldNamePlaceholder={fieldNamePlaceholder}\n fieldNameSuggestions={fieldNameSuggestions}\n showStatusProperty={(properties ?? [\"value\", \"status\"]).includes(\"status\")}\n inputFields={inputFields}\n searchSecrets={searchSecrets}\n searchConstants={searchConstants}\n onUpdate={updateCondition}\n onRemove={removeCondition}\n onAddCondition={addCondition}\n onLogicChange={changeLogic}\n />\n ))}\n {fieldNameMode === \"text\" && inputFields && (\n <FieldLegend entries={[{ key: \"/\", label: \"to insert a reference\" }]} />\n )}\n </div>\n )}\n </div>\n );\n}\n\nexport function PipesRunIfInputAdapter(field: FieldHandle<\"pipes_run_if_input\">) {\n const pipeRunIf = field.value as PipeRunIf | null;\n const meta = field.meta as PipesRunIfMeta;\n\n return (\n <ConditionBlockEditor\n value={(pipeRunIf?.when as ConditionBlockValue | undefined) ?? null}\n onChange={(block) => field.setValue(block ? { action: \"run\", when: block } : null)}\n fields={meta.fields}\n form={field.form}\n conditionsPath={`${field.path}.when.conditions`}\n />\n );\n}\n\nexport function ConditionBlockInputAdapter(field: FieldHandle<\"condition_block_input\">) {\n const block = field.value as ConditionBlockValue | null;\n const meta = field.meta as ConditionBlockMeta;\n\n return (\n <ConditionBlockEditor\n value={block}\n onChange={(next) => field.setValue(next)}\n fields={meta.fields}\n form={field.form}\n conditionsPath={`${field.path}.conditions`}\n fieldNameMode={meta.fieldNameMode}\n fieldNamePlaceholder={meta.fieldNamePlaceholder}\n fieldNameSuggestions={meta.options}\n properties={meta.properties}\n inputFields={meta.inputFields}\n searchSecrets={field.searchSecrets}\n searchConstants={field.searchConstants}\n />\n );\n}\n"],"mappings":"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"}
@@ -0,0 +1,48 @@
1
+ import { SuggestCombobox } from "../../internal/combobox/suggest-combobox.mjs";
2
+ import { useMemo } from "react";
3
+ import { jsx } from "react/jsx-runtime";
4
+
5
+ //#region src/components/defaults/adapters/typed-fields-select-input.tsx
6
+ /**
7
+ * Like `fields-select-input`, but each picked column SNAPSHOTS its
8
+ * type/format (from the option's `data`, fetched via field context) into the
9
+ * payload — the source columns live on another sheet, so their types aren't
10
+ * derivable at validate time. Free-typed names fall back to `"unknown"`.
11
+ * Entries already in the value keep their stored snapshot even when the
12
+ * option list has since changed (e.g. the sibling sheet was switched).
13
+ */
14
+ function TypedFieldsSelectInputAdapter(field) {
15
+ const entries = useMemo(() => field.value ?? [], [field.value]);
16
+ const selected = useMemo(() => entries.map((f) => f.field_name), [entries]);
17
+ const toEntry = (fieldName) => {
18
+ const existing = entries.find((e) => e.field_name === fieldName);
19
+ if (existing) return existing;
20
+ const data = (field.meta.options ?? []).find((o) => o.value === fieldName)?.data;
21
+ const type = data?.type ?? "unknown";
22
+ const format = data?.format ?? null;
23
+ return {
24
+ field_name: fieldName,
25
+ type,
26
+ ...format ? { format } : {}
27
+ };
28
+ };
29
+ return /* @__PURE__ */ jsx("div", {
30
+ "data-p0": "input",
31
+ children: /* @__PURE__ */ jsx(SuggestCombobox, {
32
+ value: selected,
33
+ onChange: (next) => field.setValue(next.map(toEntry)),
34
+ options: field.meta.options ?? [],
35
+ maxItems: field.meta.maxItems,
36
+ disableSearch: field.meta.disableSearch,
37
+ disabled: field.disabled,
38
+ ariaInvalid: !!field.error,
39
+ placeholder: field.meta.placeholder ?? "Select fields…",
40
+ emptyLabel: "No fields available",
41
+ reorderable: true
42
+ })
43
+ });
44
+ }
45
+
46
+ //#endregion
47
+ export { TypedFieldsSelectInputAdapter };
48
+ //# sourceMappingURL=typed-fields-select-input.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"typed-fields-select-input.mjs","names":[],"sources":["../../../../src/components/defaults/adapters/typed-fields-select-input.tsx"],"sourcesContent":["import type { RecordFieldFormat, RecordFieldType } from \"@pipe0/base\";\nimport { useMemo } from \"react\";\nimport type { FieldHandle } from \"../../../types/field-handle.js\";\nimport { SuggestCombobox } from \"../../internal/combobox/suggest-combobox.js\";\n\ntype TypedFieldEntry = {\n field_name: string;\n type: RecordFieldType;\n format?: RecordFieldFormat;\n};\n\n/**\n * Like `fields-select-input`, but each picked column SNAPSHOTS its\n * type/format (from the option's `data`, fetched via field context) into the\n * payload — the source columns live on another sheet, so their types aren't\n * derivable at validate time. Free-typed names fall back to `\"unknown\"`.\n * Entries already in the value keep their stored snapshot even when the\n * option list has since changed (e.g. the sibling sheet was switched).\n */\nexport function TypedFieldsSelectInputAdapter(field: FieldHandle<\"typed_fields_select_input\">) {\n const entries = useMemo<TypedFieldEntry[]>(() => field.value ?? [], [field.value]);\n const selected = useMemo(() => entries.map((f) => f.field_name), [entries]);\n\n const toEntry = (fieldName: string): TypedFieldEntry => {\n const existing = entries.find((e) => e.field_name === fieldName);\n if (existing) return existing;\n const data = (field.meta.options ?? []).find((o) => o.value === fieldName)?.data;\n const type = (data?.type as RecordFieldType | undefined) ?? \"unknown\";\n const format = (data?.format as RecordFieldFormat | undefined) ?? null;\n return { field_name: fieldName, type, ...(format ? { format } : {}) };\n };\n\n return (\n <div data-p0=\"input\">\n <SuggestCombobox\n value={selected}\n onChange={(next) => field.setValue(next.map(toEntry))}\n options={field.meta.options ?? []}\n maxItems={field.meta.maxItems}\n disableSearch={field.meta.disableSearch}\n disabled={field.disabled}\n ariaInvalid={!!field.error}\n placeholder={field.meta.placeholder ?? \"Select fields…\"}\n emptyLabel=\"No fields available\"\n reorderable\n />\n </div>\n );\n}\n"],"mappings":";;;;;;;;;;;;;AAmBA,SAAgB,8BAA8B,OAAiD;CAC7F,MAAM,UAAU,cAAiC,MAAM,SAAS,EAAE,EAAE,CAAC,MAAM,MAAM,CAAC;CAClF,MAAM,WAAW,cAAc,QAAQ,KAAK,MAAM,EAAE,WAAW,EAAE,CAAC,QAAQ,CAAC;CAE3E,MAAM,WAAW,cAAuC;EACtD,MAAM,WAAW,QAAQ,MAAM,MAAM,EAAE,eAAe,UAAU;AAChE,MAAI,SAAU,QAAO;EACrB,MAAM,QAAQ,MAAM,KAAK,WAAW,EAAE,EAAE,MAAM,MAAM,EAAE,UAAU,UAAU,EAAE;EAC5E,MAAM,OAAQ,MAAM,QAAwC;EAC5D,MAAM,SAAU,MAAM,UAA4C;AAClE,SAAO;GAAE,YAAY;GAAW;GAAM,GAAI,SAAS,EAAE,QAAQ,GAAG,EAAE;GAAG;;AAGvE,QACE,oBAAC,OAAD;EAAK,WAAQ;YACX,oBAAC,iBAAD;GACE,OAAO;GACP,WAAW,SAAS,MAAM,SAAS,KAAK,IAAI,QAAQ,CAAC;GACrD,SAAS,MAAM,KAAK,WAAW,EAAE;GACjC,UAAU,MAAM,KAAK;GACrB,eAAe,MAAM,KAAK;GAC1B,UAAU,MAAM;GAChB,aAAa,CAAC,CAAC,MAAM;GACrB,aAAa,MAAM,KAAK,eAAe;GACvC,YAAW;GACX;GACA;EACE"}